reactjs前端实践|第四篇:TodoList示例rudex、immutable-js

2

实践四

延续Todo List示例,使用redux & immutabel-js对项目进行改造。

遵循原则

  • 单一数据源(整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中)

  • State 是只读的(惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象)

  • 使用纯函数来执行修改(为了描述 action 如何改变 state tree ,需要编写 reducers)

  • Dumb组件存入于components目录中,用函数式组件来实现;Smart组件存放于containers目录中。

  • constants目录存放所有action type常量定义,actions目录存放所有action creators

代码分析

我第一步在没有使用immutable-js的情况下完成了引入redux的改造,然后再加入了immutable-js,逐步体验了各个库引入带来的变化与好处。

引入redux

新增constants/ActionTypes.js

export const ADD_TODO = 'ADD_TODO'

新增actions/index.js

import * as types from '../constants/ActionTypes'
export const addTodo = text => ({ type: types.ADD_TODO, text })

新增reducers/index.js, 统一加载reducer处理入口,方便分文件编写相同模块的处理函数。

import { combineReducers } from 'redux'
import todos from './todos'

const rootReducer = combineReducers({
  todos
})
export default rootReducer

新增reducer/todos.js, todos模块的处理函数。

import { ADD_TODO } from '../constants/ActionTypes'
import * as __ from 'lodash';

const initialState =
  {
      items:[]
  };


export default function todos(state = initialState, action) {
  switch (action.type) {
      case ADD_TODO:
          let newState = __.cloneDeep(state);        //深拷贝,不能直接改原state
          newState.items.push({key:new Date().getTime(),text:action.text});
          return newState;
    default:
      return state
  }
}

修改App.js

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as TodoActions from '../actions';    //集中放置,方便统一导入

class App extends Component {
    static propTypes = {                      //类静态变量的方式
        todos: PropTypes.array.isRequired,
        actions: PropTypes.object.isRequired
    };
    componentDidMount (){                     //具有生命周期的组件不能函数组件实现
        this.InputComponent.focus();
    };
    render() {
        var {todos,actions} = this.props;    //解构属性
        return (
            <div>
                <InputAndButton ref={comp => { this.InputComponent = comp; }} onSave={actions.addTodo}/>
                <LiList items={todos}/>
            </div>
        );
    };
}

const mapStateToProps = state => ({
    todos: state.todos.items          //注意,这块是state.todos.items,中间的todos是因底层封装被带入,不能少,多用工具观察state结构,能明白不少问题。
})

const mapDispatchToProps = dispatch => ({
    actions: bindActionCreators(TodoActions, dispatch)      //统一引入,这块能很简洁
})

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(App)

修改index.js

import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './reducers'

const store = createStore(reducer)                //初始化state
render(
    <Provider store={store}>                      //加载应用
        <App />
    </Provider>,
    document.getElementById('root')
);

引入immutable-js

为避免对象的深拷贝,使用Immutable,它提供了简洁高效的判断数据是否变化的方法,可以极大提高性能。我使用redux-immutable完成改造。

修改src/reducers/index.js

-import { combineReducers } from 'redux'
+import { combineReducers } from 'redux-immutable'       //切换组合函数
 import todos from './todos'
 const rootReducer = combineReducers({                   //其余地方无需改变
        ...

修改src/reducers/todos.js

 import { ADD_TODO } from '../constants/ActionTypes' 
-import * as __ from 'lodash';                 //不再需要辅助函数
+import {Map, List} from 'immutable';          //引入immutable的相应数据结构
-const initialState =
-  {
-      items:[]
-  };
+let initialState = Map({                      //使用immutable-js数据结构
+        items: List([])
+    });
 export default function todos(state = initialState, action) {
   switch (action.type) {
       case ADD_TODO:
-          let newState = __.cloneDeep(state);
-          newState.items.push({key:new Date().getTime(),text:action.text});
-          return newState;
+          return state.update('items', value => value.push({key:new Date().getTime(),text:action.text}));            //操作更加简洁
     default:
       return state
   }

修改src/containers/App.js

 const mapStateToProps = state => ({
-    todos: state.todos.items
+    todos: state.get('todos').get('items')         //使用immutable-js的Map操作接口
 })

项目地址

https://git.oschina.net/zhoutk/reactodo.git
https://github.com/zhoutk/reactodo.git

使用方法

git clone https://git.oschina.net/zhoutk/reactodo.git
or git clone https://github.com/zhoutk/reactodo.git
cd reactodo
npm i
git checkout todo_list_react
npm start

小结

这次实践,理解了redux的原理,学会了如何利用redux来改造我们的项目;并且利用immutable-js优化了state的操作及性能。


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

Jiong · 2017年05月09日

想请教您一下 引入immutable后 props应该设定为immutable吗?

回复

1

props是组件接收的参数(属性),因为state已经是immutable了,大部分时候所有组件接收的都是state树的某个子树,当然是immutable了,但你也可以给组件传递mutable参数。
上面是我的理解,不知道是否是你想要的,仅供参考。

zhoutk 作者 · 2017年05月09日
lloyd_zhou · 2017年09月20日

这几天写了一个前端组件库,gzip之后只有900byte,而且还是零依赖( https://github.com/lloydzhou/... ),用这个库实现了一下todo MVC的demo ( https://lloydzhou.github.io/t... )。

回复

载入中...