六、使用redux管理数据

2019-12-12  本文已影响0人  风之伤_3eed

一、安装redux 、redux-pack、redux-thunk

npm i redux redux-pack redux-thunk
参考网站:reduxredux-thunkredux-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);
上一篇下一篇

猜你喜欢

热点阅读