随着react hooks的出现我们越来越多的项目已经转由hooks来写,没有看过之前关于hooks的介绍的同学们可以移步
那么我们如果需要路由或者状态之类的支持时我们就需要用到umi和dva。
= umi@2起,dva的整合可以直接通过 umi-plugin-react 来配置
我们当然可以看官方demo
我们今天结合官方文档来完成属于自己的react hooks结合umi的例子
我们这个例子是创建一个聊天机器人的前端界面
yarn create umi
具体是否需要到dva还是antd根据自己需求而定
image.png首先我们假定这个聊天机器人有两个页面第一个为主页通过主页我们有一个弹框可以进入一个聊天界面
首先我们先配置路由
在.umirc.js中配置为chat的路径
routes: [
{
path: '/',
component: '../layouts/index',
routes: [
{ path: '/', component: '../pages/index' },
{ path: '/chat', component: '../pages/chat' } // 有一个为chat的页面
]
}
]
接下来我们修改我们首页
//index.js
import React from 'react';
import styles from './index.css';
import handshake from '../assets/handshake.png';
import { Button } from 'antd';
export default function() {
const handleClick = () => {
window.open("/chat", "newwindow", "height=600, width=440, top=0, left=400, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no, status=no");
}
return (
<div className={styles.container}>
<p className={styles.slogan}>AccessHub Chatbot</p>
<div className={styles.f1}>
<Button className={styles.font} onClick={handleClick} style={{background: '#20B2AA', color: '#faf0e6', fontFamily: 'IBMPlexSans,Helvetica Neue,Helvetica,Arial,sans-serif', width: '300px', height: '60px'}}>Click here to talk with me </Button>
</div>
<div className={styles.logo}>
<img className={styles.image} src={handshake} />
</div>
</div>
);
}
image.png
当我们点击中间button是就会到我们的/chat里
接下来我们在pages里创建chat的文件夹在里面创建对应的modles services
眼尖的同学们发现了我们用了sass 我们可以用任意的sass或者less
如果是sass的话我们需要
yarn add node-sass sass-loader
image.png
我们先从services开始
创建chat.js
如果我们要请求一些接口我们就放在services里已机器人为例我么现在需要两个接口一个是获取进来的用户的信息一个是问机器人问题
import request from '../../../utils/request';
export function getUser() {
return request('/user_infos');
}
export function ask(data) {
return request('/answers', {
method: 'POST',
body: JSON.stringify(data),
});
}
这是我们在src目录创建一个utils文件夹创建request.js来方便我们请求
import { fetch } from 'dva';
const domain = 'url location'; // http://0.0.0.0:8000
function parseJSON(response) {
console.log(response)
return response.json();
}
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} [options] The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default function request(url, options) {
console.log(domain+url)
return fetch(domain+url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => ({ data }))
.catch(err => ({ err }));
}
接下来我们在models创建chat.js
在 umi 项目中,你可以使用 dva 来处理数据流,以响应一些复杂的交互操作。这些处理数据流的文件统一放在 models 文件夹下,每一个文件默认导出一个对象,里面包含数据和处理数据的方法,通常我们称之为 model
- namespace: 当前 Model 的名称。整个应用的 State,由多个小的 Model 的 State 以 namespace 为 key 合成
- state: 该 Model 当前的状态。数据保存在这里,直接决定了视图层的输出
- reducers: Action 处理器,处理同步动作,用来算出最新的 State
- effects:Action 处理器,处理异步动作
- subscriptions: 一般我们在页面初始化时会用到subscriptions
namespace
文件名即 namespace,可以省去 model 导出的 namespace key
namespace: 'chat'
state
将要用到的数据保存进去
state: {
userInfo: {},
answer: {},
question: ''
},
subscriptions
初始化时判断是否一来就要发起请求
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, query }) => {
if (pathname === '/chat') {
dispatch({ type: 'fetch' });
}
});
},
},
effects
异步操作调service里两个接口
*fetch({ payload }, { call, put }) { // eslint-disable-line
console.log(payload, chatService.getUser)
const userInfo = yield call(chatService.getUser);
console.log(userInfo)
yield put({
type: 'save',
payload: userInfo.data,
});
},
*ask({ payload }, { call, put, select }) {
const res = yield call(chatService.ask, payload);
console.log(res)
yield put({ type: 'askQuestion', payload: {"answer": res.data}});
},
reducers
同步操作返回最新state
reducers: {
save(state, { payload }) {
console.log(payload)
return { ...state, userInfo: payload };
},
askQuestion(state, { payload }) {
console.log(payload)
return { ...state, answer: payload.answer};
},
saveQuestion(state, { payload }) {
console.log(payload)
return { ...state, question: payload.question};
},
},
接下来我们创建mock数据方便测试
为了模拟真实延迟我们让所有的接口都延迟一秒返回
需要用到roadhog-api-doc
import { delay } from 'roadhog-api-doc';
const proxy = {
'GET /user_infos': {username: 'ddw', s_n: "04599A672", email:"jorgegong@163.com"},
'POST /answers': (req, res) => {
res.send({ answer: 'hello', image: '' });
},
};
// 调用 delay 函数,统一处理
export default delay(proxy, 1000);
这里页面上部分可以参照之前关于hooks的介绍,想看代码的同学可以干住下我的github
网友评论