React 实践项目 (二)

React在Github上已经有接近70000的 star 数了,是目前最热门的前端框架。而我学习React也有一段时间了,如今就开始用 React+Redux 进行实战!css

React 实践项目 (一)

本次实践代码html

部署好的网址前端

上回说到用React写了一个带Header的首页,咱们此次实践就使用Redux进行状态管理

index

Rudex

应用中全部的 state 都以一个对象树的形式储存在一个单一的 store 中。
唯一改变 state 的办法是触发 action,一个描述发生什么的对象。
为了描述 action 如何改变 state 树,你须要编写 reducers。vue

咱们接下来开始开始进行登录与注册的状态管理node

首先在 src 目录下建立 redux 文件夹,目录以下react

digag
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   └── favicon.ico
│   └── index.html
│   └── manifest.json
└── src
    └── components
        └── Index
            └── Header.js
            └── LoginDialog.js
            └── RegisterDialog.js
    └── containers
        └── App
            └── App.js
            └── App.css
    └── redux
        └── action
            └── users.js
        └── reducer
            └── auth.js
            └── users.js
        └── sagas
            └── api.js
            └── sagas.js
            └── selectors.js.js
            └── users.js
        └── store
            └── store.js
    └── App.test.js
    └── index.css
    └── index.js
    └── logo.svg
    └── registerServiceWorker.js

代码可今后获取git

记得在 package.json 中更新依赖github

接下来我会开始解释关键代码

  • action
    action/users.js
/*
 * action 类型
 */
export const REGISTER_USER = 'REGISTER_USER';
// 省略其余action 类型

/*
 * action 建立函数
 */
export const registerAction = (newUser) => {
  return{
    type:REGISTER_USER,
    data: newUser,
  }
};
// 省略其余 action 建立函数
  • reducer
    reducer/users.js
//Immutable Data 就是一旦建立,就不能再被更改的数据。
//对 Immutable 对象的任何修改或添加删除操做都会返回一个新的 Immutable 对象。
import Immutable from 'immutable';
//从 action 导入须要的 action 类型
import {REGISTER_USER, REGISTER_USER_SUCCESS, REGISTER_USER_FAILURE} from '../action/users';

// 初始化状态
const initialState = Immutable.fromJS({
  newUser: null,
  error: null,
  saveSuccess: false,
});

//  reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
export const users = (state = initialState, action = {}) => {
  switch (action.type) { // 判断 action 类型
    case REGISTER_USER:  
      return state.merge({   // 更新状态
        'newUser': action.data,
        'saveSuccess': false,
        'error': null,
      });
    case REGISTER_USER_SUCCESS:
      return state.set('saveSuccess', action.data);
    case REGISTER_USER_FAILURE:
      return state.set('error', action.data);
    default:
      return state
  }
};
  • store
    store/store.js
import {createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga'
import * as reducer from '../reducer/users';

import rootSaga from '../sagas/sagas';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  combineReducers(reducer),
  applyMiddleware(sagaMiddleware)
);

sagaMiddleware.run(rootSaga);

export default store;

而后在入口文件使用 store

src/index.jsjson

import {Provider} from 'react-redux';
import store from './redux/store/store';
// 省略其余

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>, document.getElementById('root')
);

在 App.js 中获取 action 和 状态

import {registerAction, loginAction} from '../../redux/action/users';
import {connect} from "react-redux";
import {bindActionCreators} from "redux";
 //省略其余

class App extends Component {

  render(){
    return(
      <div className="App">
        //省略
      </div>
    )
  }

}

export default connect(
  (state) => {
// 获取状态   state.users  是指 reducer/users.js 文件中导出的 users
// 能够 `console.log(state);` 查看状态树
  return { users: state.users }
},
  (dispatch) => {
  return {
// 建立action
    registerActions: bindActionCreators(registerAction, dispatch),
    loginActions: bindActionCreators(loginAction, dispatch),
  }
})(App);
// 在App 组件的props里就有 this.props.users  this.props.registerActions this.props.loginActions 了
// 须要注意的是这里this.props.users是Immutable 对象,取值须要用this.props.users.get('newUser') 
// 也可在 reducer 里改用 js 普通对象

装饰器版本:
须要在Babel中开启装饰器
装饰器插件babel-plugin-transform-decorators-legacyredux

@connect(
  (state) => {
    console.log(state);
    return ({
      users: state.users,
    });
  },
  {registerActions: registerAction, loginActions: loginAction}
)

最后把 registerActions 传给RegisterDialog子组件,

src/components/Index/RegisterDialog.js

// 省略其余代码
 handleSubmit = (e) => {
    e.preventDefault();
    // 验证表单数据
    this.refs.user.validate((valid) => {
      if (valid) {
        // this.state.user 为表单收集的 用户注册数据
        this.props.registerActions(this.state.user);
        this.setState({loading: true});
      }
    });
  };

流程是:

  • 调用 action
    this.props.registerActions(this.state.user);
    返回action 为
{
    type:REGISTER_USER,
    data: this.state.user,
}
  • reducer 根据action类型更新状态
switch (action.type) {
    case REGISTER_USER:
      return state.merge({
        'newUser': action.data,
        'saveSuccess': false,
        'error': null,
      });
//省略其余代码

这时咱们的store里的状态 newUser就被更新为 注册弹窗里收集的数据
到这里都仍是同步的action,而注册是一个异步的操做。
下篇文章会介绍如何使用 redux-saga 进行异步操做。
redux-saga 已经在使用了,有兴趣的能够自行查看代码理解。

记得点star:)
项目代码地址:https://github.com/DigAg/digag-pc-react
vue2版项目代码地址:https://github.com/DigAg/digag-pc-vue2
相应后端项目代码地址:https://github.com/DigAg/digag-server

相关文章
相关标签/搜索