使用UmiJS框架开发React应用
<span id="top"><p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>1)、简介</li><li>2)、安装<ul><li>2.1)、安装 nodejs</li><li>2.2)、安装 yarn</li><li>2.3)、安装 umi</li></ul></li><li>3)、使用 umi<ul><li>3.1)、创建项目</li><li>3.2)、初始化</li><li>3.3)、开发工具打开</li><li>3.4)、运行项目</li></ul></li><li>4)、分层开发<ul><li>4.1)、过程图示</li><li>4.2)、开始开发<ul><li>4.2.1)、添加依赖</li><li>4.2.2)、antd基本布局</li><li>4.2.3)、Service异步请求数据</li><li>4.2.4)、Mock模拟数据</li><li>4.2.5)、Model层中引入该 js 文件用于异步请求</li><li>4.2.6)、Page层引入Model层的数据和方法</li></ul></li><li>4.3.)、umi-plugin-react插件升级</li></ul></li></ul></div><p></p>
<h2 id="1简介">1)、简介</h2>
<p><code>UmiJS</code>读音:(乌米) <br>
<code>UmiJS</code>是一个可插拔的企业级<code>React</code>应用框架。官网地址是:https://umijs.org/zh/</p>
<p>特点:</p>
<ul>
<li>
<p><strong>插件化</strong> <br>
<code>umi</code>的整个生命周期都是插件化的,甚至其内部实现就是由大量插件组成,比如:pwa、按需加载、一键切换 <code>preact</code>、一键兼容 ie9 等等,都是由插件实现。</p>
</li>
<li>
<p><strong>开箱即用</strong> <br>
你只需一个<code>umi</code>依赖就可启动开发,无需安装<code>react</code>、<code>preact</code>、<code>webpack</code>、<code>react-router</code>、<code>babel</code>、<code>jest</code>等等。</p>
</li>
<li>
<p><strong>约定式路由</strong> <br>
类似<code>next.js</code>的约定式路由,无需再维护一份冗余的路由配置,支持权限、动态路由、嵌套路由等等。</p>
</li>
</ul>
<h2 id="2安装">2)、安装</h2>
<h3 id="21安装-nodejs">2.1)、安装 nodejs</h3>
<p>要使用<code>UmijS</code>首先要安装<code>nodejs</code>环境,在Mac下安装<code>nodejs</code>:</p>
<pre><code class="language-shell"> brew install nodejs
</code></pre>
<p>windows下安装,需要到官网下载安装程序,然后下一步下一步完成即可,也非常简单。这里不介绍了,也可自行百度,网上有很多。</p>
<h3 id="22安装-yarn">2.2)、安装 yarn</h3>
<p>可以把<code>yarn</code>看做了优化了的<code>npm</code>,其中<code>tyarn</code>使用的是npm.taobao.org的源,速度要快一些。平常使用的话使用<code>tyarn</code>即可。</p>
<pre><code class="language-shell">npm i yarn tyarn -g --registry=https://registry.npm.taobao.org
</code></pre>
<h3 id="23安装-umi">2.3)、安装 umi</h3>
<pre><code class="language-shell">tyarn global add umi
</code></pre>
<p>查看是否安装成功:</p>
<pre><code>umi -v
</code></pre>
<p>如果出现 <code>'umi' 不是内部或外部命令,也不是可运行的程序 或批处理文件</code>或者提示 <code>umi: command not found</code></p>
<p><img src="https://img2018.cnblogs.com/blog/1405402/201906/1405402-20190626121056093-977675581.png" alt="" loading="lazy"></p>
<h2 id="3使用-umi">3)、使用 umi</h2>
<h3 id="31创建项目">3.1)、创建项目</h3>
<pre><code class="language-shell">mkdir ~/Documents/umi-demo
</code></pre>
<h3 id="32初始化">3.2)、初始化</h3>
<p>进入到项目文件夹下</p>
<pre><code class="language-shell">cd ~/Documents/umi-demo
</code></pre>
<p>再创建<code>umi</code>其他默认的目录,这些默认的目录名字不能写错。</p>
<pre><code>mkdir -p {config,mock,src/pages,src/models,src/layouts}
</code></pre>
<blockquote>
<p><code>config/</code>: 该目录下的<code>config.js</code>默认是全局的配置 <br>
<code>mock/</code>: 模拟后端请求数据的js目录<br>
<code>src/</code>: 代码目录 <br>
<code>pages/</code>: 为前端页面, 页面的后缀名可以是.js或者.jsx <br>
<code>models/</code>: 为数据层, 处理数据的 js 文件 <br>
<code>layouts/</code>: 默认是整个项目的基础布局文件</p>
</blockquote>
<p>通过初始化命令将生成<code>package.json</code>文件,它是<code>NodeJS</code>约定的用来存放项目的信息和配置等信息的文件。</p>
<pre><code class="language-shell">tyarn init -y
</code></pre>
<p>为项目设置一个默认的展开页面,因为<code>umiJS</code>在后台启动时会默认加载<code>src/pages/index.js</code>文件。使用下面命令可以通过umi命令创建index.js文件。</p>
<pre><code class="language-shell">umi g page index
</code></pre>
<p>可以看到在pages下创建好了index.js和index.css文件。</p>
<h3 id="33开发工具打开">3.3)、开发工具打开</h3>
<p><img src="https://note.youdao.com/yws/public/resource/ee2140251b2fec088b63a8988bb9c2b2/xmlnote/WEBRESOURCE32f8b252cd9e8c46044fd2821e34939f/11899" alt="1" loading="lazy"></p>
<p>目录结构</p>
<p><img src="https://note.youdao.com/yws/public/resource/ee2140251b2fec088b63a8988bb9c2b2/xmlnote/WEBRESOURCE969086965c947754a19cbbe84e2c79ee/11950" alt="2" loading="lazy"></p>
<h3 id="34运行项目">3.4)、运行项目</h3>
<pre><code>umi dev
</code></pre>
<p><img src="https://note.youdao.com/yws/public/resource/ee2140251b2fec088b63a8988bb9c2b2/xmlnote/WEBRESOURCEf793f345783441494c6dbe26b35f54e8/11964" alt="3" loading="lazy"></p>
<p>访问: http://localhost:8000</p>
<h2 id="4分层开发">4)、分层开发</h2>
<h3 id="41过程图示">4.1)、过程图示</h3>
<p><img src="https://note.youdao.com/yws/public/resource/ee2140251b2fec088b63a8988bb9c2b2/xmlnote/WEBRESOURCE43a9a97bfd361106816fdc7e5e5a7561/11991" alt="5" loading="lazy"></p>
<p>说明:</p>
<p>上图中,左边是用户,中间为前端,右边为后端。我们对前端进行分层,可以分为<code>Page</code>、<code>Model</code>、<code>Service</code>3层。</p>
<ul>
<li><code>Page</code> 负责与用户直接打交道:渲染页面、接受用户的操作输入,侧重于展示型交互 性逻辑。</li>
<li><code>Model</code> 负责处理业务逻辑,为 Page 做数据、状态的读写、变换、暂存等。</li>
<li><code>Service</code> 负责与 HTTP 接口对接,进行纯粹的数据读写。</li>
</ul>
<p>其中 <code>Page</code>层通过<code>UmiJS</code>的<code>umi-plugin-react</code>插件的<code>dva</code>功能,可以调用<code>Model</code>层定义的数据和方法;<code>Model</code>层通过<code>import</code>定义的异步请求函数<code>request.js</code>来调用<code>Service</code>层;而<code>Service</code>层就是去后端请求数据。</p>
<h3 id="42开始开发">4.2)、开始开发</h3>
<h4 id="421添加依赖">4.2.1)、添加依赖</h4>
<p>添加<code>umi</code>的依赖</p>
<pre><code class="language-shell">tyarn add umi --dev
</code></pre>
<p>添加<code>umi-plugin-react</code>插件</p>
<pre><code class="language-shell">tyarn add umi-plugin-react --dev
</code></pre>
<p>添加<code>.gitignore</code>文件</p>
<pre><code class="language-text">node_modules
dist
.umi
</code></pre>
<p>在<code>config/config.js</code>配置中引入<code>umi-plugin-react</code>插件</p>
<pre><code class="language-js">export default {
plugins: [
['umi-plugin-react', {
dva: true,
antd: true
}]
]
};
</code></pre>
<h4 id="422antd基本布局">4.2.2)、antd基本布局</h4>
<p>添加基本布局和样式:<br>
在<code>layouts</code>文件目录下创建<code>index.js</code>文件,在<code>index.js</code>中我们写入:</p>
<pre><code>import { Component } from 'react';
import { Layout } from 'antd';
// Header, Footer, Sider, Content组件在Layout组件模块下
const { Header, Footer, Sider, Content } = Layout;
class BasicLayout extends Component {
render() {
return (
<Layout>
<Sider width={256} style={{ minHeight: '100vh', color: 'white' }}>
Sider
</Sider>
<Layout >
<Header style={{ background: '#fff', textAlign: 'center', padding: 0 }}>Header</Header>
<Content style={{ margin: '24px 16px 0' }}>
<div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
{this.props.children}
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
)
}
}
export default BasicLayout;
</code></pre>
<blockquote>
<p>上面代码中,我们创建了一个三部分的基本布局:Header 、Content 、Footer。然后我们将 Content 替换成 { this.props.children },这样之后我们设置的路由会通过替换 children 变量实现内容的切换。</p>
</blockquote>
<p>上面需要引入的组件都安装好了之后,我们就可以来编写我们的前端代码了。我们可以根据上面的图,按照从下到上的顺序进行编写,也就是<code>Service</code>→<code>Model</code>→<code>Page</code>来进行。</p>
<h4 id="423service异步请求数据">4.2.3)、Service异步请求数据</h4>
<p>在 src 目录下创建 utils 目录, 创建 request.js 文件</p>
<pre><code class="language-js">function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
/**
* Requests a URL, returning a promise.
*
* @param {string} url The URL we want to request
* @param {object} The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default async function request(url, options) {
const response = await fetch(url, options);
checkStatus(response);
return await response.json();
}
</code></pre>
<h4 id="424mock模拟数据">4.2.4)、Mock模拟数据</h4>
<p>在 mock目录下创建UserList.js文件,用来模拟数据。因为有了umi默认集成了mock功能,所以只要编写mock数据即可。</p>
<pre><code class="language-js">export default {
'get /ds/list' : function (req, res) {
res.json({
data: ['zhangsan','lisi','wangwu']
})
}
}
</code></pre>
<h4 id="425model层中引入该-js-文件用于异步请求">4.2.5)、Model层中引入该 js 文件用于异步请求</h4>
<pre><code class="language-js">import request from '../../utils/request'
export default {
namespace: 'user',
//该模型中的一些属性
state: {
data: []
},
//一些正常的同步方法
reducers: {
//state是原先的数据,result是effets中异步调用返回的数据
save(state, result){
//如果 result.data中存在数据,表示该函数是被异步调用初始化。直接返回
if (result.data){
return result.data;
}
let list = [...state.data, 'freeman'];
//返回更新后的state对象
return {
data: list
}
}
},
effects: {
// 这里定义异步方法
*initData(params, sagaEffects) { //定义异步方法
const {call, put} = sagaEffects; //获取到call、put方法
const url = "/ds/list"; // 定义请求的url
let result = yield call(request, url); //执行请求
yield put({ // 调用reducers中的方法
type : "save", //指定方法名
data : result//传递ajax回来的数据, 注意 put 会指定调用的同步方法,
//该调用的方法会在定义的方法的入参添加一个参数(result), 使用该参数才能获取到put方法,取到的值
});
}
}
}
</code></pre>
<p>DVA 的 model 对象有几个基本的属性,需要大家了解。</p>
<ul>
<li><code>namespace</code>:<code>model</code> 的命名空间,只能用字符串。一个大型应用可能包含多个 <code>model</code>,通过<code>namespace</code>区分。</li>
<li><code>state</code>:当前 <code>model</code> 状态的初始值,表示当前状态。</li>
<li><code>reducers</code>:用于处理同步操作,可以修改 <code>state</code>,由 <code>action</code> 触发。<code>reducer</code> 是一个纯函数,它接受当前的 <code>state</code> 及一个数据体(<code>payload</code>)作为入参,返回一个新的 <code>state</code>。</li>
<li><code>effects</code>:用于处理异步操作(例如:与服务端交互)和业务逻辑,也是由 <code>action</code> 触发。但是,它不可以修改 state,要通过触发 <code>action</code> 调用 <code>reducer</code> 实现对 <code>state</code> 的间接操作。</li>
<li><code>action</code>:是 <code>reducers</code> 及 <code>effects</code> 的触发器,一般是一个对象,形如<code>{ type: 'add', payload: todo }</code>,通过 <code>type</code> 属性可以匹配到具体某个<code>reducer</code> 或者 <code>effect</code>,<code>payload</code> 属性则是数据体,用于传送给 <code>reducer</code> 或 <code>effect</code>。</li>
</ul>
<h4 id="426page层引入model层的数据和方法">4.2.6)、Page层引入Model层的数据和方法</h4>
<blockquote>
<p>dva是基于 redux、redux-saga 和 react-router 的轻量级前端框架。官 网:https://dvajs.com/</p>
</blockquote>
<p><code>@connect(mapStateToProps, mapDispatchToProps)</code> 需要2个参数:</p>
<ul>
<li>
<p><code>mapStateToProps</code>:是一个方法,该方法的返回值是一个属性对象{},它的作用是将这个包含state属性的对象注入到this.props中。组件通过this.props.xx的方式即可获取到model中的数据。</p>
<ul>
<li>① 、umi框架启动,会自动读取models目录下所有model文件,(如:user/List.js中的数据 )</li>
<li>②、这些model数据 会进入到<code>mapStateToProps</code>方法中</li>
<li>③、在全局的数据中,会有很多,所以需要通过namespace进行区分,所以通过<code>state</code>进行获取数据</li>
<li>④、拿到model数据中的data,也就是<code>['zhangsan','lisi','wangwu']</code>数据,进行包裹{}后返回</li>
<li>⑤、返回的数据,将被封装到<code>this.props</code>中,所以通过<code>this.props.listData</code>即可获取到 model中的数据。</li>
</ul>
</li>
<li>
<p><code>mapDispatchToProps</code>: 是一个方法,它的返回值是一个函数对象{}, 它的作用是将这些函数注入到this.props中。</p>
<ul>
<li>①、所以可以把<code>Model</code>中暴露的方法绑定到当前的组件中,定义一个方法接收,然后可以绑定到<code>onClick</code>事件上,就可以实现点击操作;也可以在页面加载完的时候拿到数据对页面进行渲染的操作(只需要绑定到生命周期函数上即可)。</li>
<li>②、dispatch 函数就是和 dva model 打交道的唯一途径。 dispatch 函数接受一个 对象 作为入参,在概念上我们称它为 action,唯一强制要包含的是 type 字段,string 类型,用来告诉 dva 我们想要干什么。我们可以选择给 action 附着其他字段,这里约定用 payload字段表示额外信息。</li>
</ul>
</li>
</ul>
<p>在 <code>pages</code>目录下新建<code>user/List.js</code>(或<code>List.jsx</code>)页面,使用快捷键<code>rcc</code>或<code>rccp</code>可以快速生成react组件。</p>
<pre><code>import React, {Component} from 'react';
import { connect } from 'dva';
const namespace = 'user';
const mapStateToProps = (state)=>{
let listData = state.data;
return {listData}
};
const mapDispatchToProps = (dispatch) => {
// 定义方法,dispatch是内置函数
return { //返回的这个对象将绑定到this.props对象中
addUser : () =>{
// 定义方法
dispatch({ // 通过调用dispatch()方法,调用model中reducers的方法
type: `${namespace}/save` // 指定方法,格式: namespace/方法名
});
},
userList : () => { //新增初始化方法的定义
dispatch({
type: `${namespace}/initData`
});
}
}
}
@connect(mapStateToProps, mapDispatchToProps)
class List extends Component {
componentDidMount() {
this.props.userList();
}
render() {
return (
<div>
<ul>
{
this.props.listData.map(
(v, i) => {return <li key={i}>{v}</li>}
)
}
</ul>
<button onClick={() => {this.props.addUser()}}>
添加
</button>
</div>
);
}
}
export default List;
</code></pre>
<h3 id="43umi-plugin-react插件升级">4.3.)、umi-plugin-react插件升级</h3>
<p>在运行 <code>umi dev</code> 或 <code>umi build</code> 运行或部署应用是,有时候会出现 “Path must be a string”错误。解决方法:</p>
<p>按照官网升级umi-plugin-react的版本。</p>
<ul>
<li>①、 package.json文件</li>
</ul>
<pre><code>{
"devDependencies": {
- "umi-plugin-react": "^1"
+ "@umijs/preset-react": "^1"
}
}
</code></pre>
<ul>
<li>②、 config/config.js文件</li>
</ul>
<pre><code>export default {
- plugins: [
- ['umi-plugin-react', {
- dva: {},
- antd: {},
- ...
- }]
- ],
+ dva: {},
+ antd: {},
+ ...
}
</code></pre>
<p>可以参考:https://umijs.org/docs/upgrade-to-umi-3#升级-umi-plugin-react-为-umijspreset-react</p>
<p>项目地址: https://gitee.com/zhaoxxnbsp/umi-demo.git</p>
<p>返回顶部↑</p>
</span><br><br>
来源:https://www.cnblogs.com/zhaoxxnbsp/p/12672652.html
頁:
[1]