六、使用redux管理数据
2019-12-12 本文已影响0人
风之伤_3eed
一、安装redux 、redux-pack、redux-thunk
npm i redux redux-pack redux-thunk
参考网站:redux、redux-thunk、redux-pack
二、在src/config下新建store.ts文件写入
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk'; // 实现异步发送请求
import { middleware as reduxPackMiddleware } from 'redux-pack';
import rootReducer from '../reducers';
const store = createStore(
rootReducer,
applyMiddleware(thunkMiddleware, reduxPackMiddleware)
);
export default store
三、新建src/actions文件夹
actions 文件夹下index.ts只负责统一导出
actions文件夹下新建user.ts写如如下代码
import { api } from '../config';
import { wrapServer } from '../config/axios'
export enum ACTION_TYPE {
LOGIN = 'LOGIN',
LOGOUT = 'LOGOUT'
}
export const login = (data: any) => {
return {
type: ACTION_TYPE.LOGIN,
promise: wrapServer({
method: 'post',
url: api.login,
data,
}),
};
};
export const logout = () => {
return {
type: ACTION_TYPE.LOGOUT,
promise: wrapServer({
method: 'post',
url: api.logout,
}),
};
};
export default {
ACTION_TYPE,
};
注:actions文件夹下不同文件负责不同模块下的请求,如果有新的模块可以在actions文件夹下新建相对应的文件,在同一模块下新增请求需要在ACTION_TYPE添加一个唯一type,导出一个新的请求。
四、新建src/reducers文件夹
新建index.tsx文件写入如下代码(每新增一个reducers文件下的文件需要在该文件内通过combineReducers合并)
import { combineReducers } from 'redux';
import { default as user } from './user';
export default combineReducers({
user,
})
新建user.ts文件写入如下代码(在这里可以对返回后的数值进行处理)
import { handle } from 'redux-pack';
import { User } from '../actions';
const { ACTION_TYPE } = User;
// 写入请求前默认数值
const initialState = {
user: {}
}
export default (state = initialState, action: any) => {
const { type, payload } = action;
switch (type) {
// 根据唯一type来匹配相应action
case ACTION_TYPE.LOGIN:
return handle(state, action, {
start: prevState => ({ ...prevState, loading: true}),
finish: prevState => ({ ...prevState, loading: false }),
failure: prevState => ({ ...prevState, user: state.user }),
success: prevState => ({ ...prevState, user: payload.data }),
});
default:
return state;
}
}
五、还需在src/App.tsx文件下引入Provider和store
修改src/App.tsx文件
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
} from "react-router-dom";
import Login from './pages/login';
import Layout from './layout';
import { Provider } from 'react-redux';
import store from './config/store';
import 'rsuite/dist/styles/rsuite-default.css';
import "./App.css";
const App = () => {
return (
<Provider store={store}>
<Router>
<Switch>
<Route exact path="/login"
component = {(props: any) => <Login { ...props } /> }
/>
<Route path="/"
component = {(props: any) => <Layout { ...props } /> }
/>
</Switch>
</Router>
</Provider>
);
};
export default App;
六、在页面发送请求接收数据
在src/pages/login修改index.tsx文件
引入connect
import { connect } from 'react-redux';
发送及从redux获取参数
const mapDispatchToProps = (dispatch: any) => ({
login: (value: any) => dispatch(login(value)),
});
const mapStateToProps = (user: any) => ({ user });
使用connect连接redux
export default connect(mapStateToProps, mapDispatchToProps)(Login);
页面完整代码
import React, { useState } from "react";
import { connect } from 'react-redux';
import {
Container,
Content,
FlexboxGrid,
Panel,
Form,
FormGroup,
ControlLabel,
FormControl,
ButtonToolbar,
Button,
Schema
} from "rsuite";
import {
login
} from '../../actions/user';
import { setToken } from '../../config/localStorage';
import './login.css';
const { StringType } = Schema.Types;
const mapDispatchToProps = (dispatch: any) => ({
login: (value: any) => dispatch(login(value)),
});
const mapStateToProps = (user: any) => ({ user });
interface Props {
history: any;
login: (value: any) => any;
user: any;
}
const Login = (props: Props) => {
const [formValue, setFormValue] = useState<any>({
name: '',
password: ''
});
const [form, setForm] = useState<any>(null);
// 自定义表单规则
const asyncCheckUsername = (name: any): any => {
console.log(name)
return new Promise(resolve => {
setTimeout(() => {
if (name === 'abc') {
resolve(false);
} else {
resolve(true);
}
}, 500);
});
}
// 验证表单规则
const model = Schema.Model({
name: StringType()
.isRequired('请填写用户名.')
.addRule((value, data) => {
return asyncCheckUsername(value);
}, '用户已注册'),
password: StringType()
.isRequired('请填写密码.')
});
// 提交
const handleSubmit = () => {
form.checkAsync().then((result: any) => {
if (!result.hasError) {
发送登录请求
props.login(formValue)
.then(
(res: any) => {
if (!res.error) {
// 当登录成功时时跳转到控制台首页
setToken(res.payload.data)
props.history.push('/')
}
}
)
}
});
}
return (
<div className="show-fake-browser login-page">
<Container>
<Content>
<FlexboxGrid justify="center">
<FlexboxGrid.Item colspan={12}>
<Panel header={<h3>登录</h3>} bordered>
<Form
ref={(ref: any) => (setForm(ref))}
fluid
onChange={formValue => {
setFormValue(formValue)
}}
onCheck={formError => {
}}
formValue={formValue}
model={model}
>
<FormGroup>
<ControlLabel>用户名</ControlLabel>
<FormControl name="name" />
</FormGroup>
<FormGroup>
<ControlLabel>密码</ControlLabel>
<FormControl name="password" type="password" />
</FormGroup>
<FormGroup>
<ButtonToolbar>
<Button appearance="primary" onClick={handleSubmit}>登录</Button>
{/* <Button appearance="link">Forgot password?</Button> */}
<span style={{paddingLeft: 20}}>用户名:admin 密码:123456</span>
</ButtonToolbar>
</FormGroup>
</Form>
</Panel>
</FlexboxGrid.Item>
</FlexboxGrid>
</Content>
{/* <Footer>xxx公司</Footer> */}
</Container>
</div>
);
};
export default connect(mapStateToProps, mapDispatchToProps)(Login);