#8 immutable在redux中的使用,TodoApp

immutable在redux中的应用主要集中在reducers中对state数据的操作上。

可以参考 stackoverflow中的问题

下面和结合一个实例关于immutable部分的介绍和注意的问题。

不使用immutable时的写法

数据结构(普通的对象数据):

const dummyTodos = [
  { id: 0, isDone: true,  text: 'make components' },
  { id: 1, isDone: false, text: 'design actions' },
  { id: 2, isDone: false, text: 'implement reducer' },
  { id: 3, isDone: false, text: 'connect components' }
];   

纯组件:

const Todo = ({ todo }) => {
  if (todo.isDone) {
    return <strike>{todo.text}</strike>
  }
  return <span>{todo.text}</span>
};

const TodoList = ({ todos }) => {
  return (
    <div>
      <input
        type="text"
        placeholder="add a task"
      />
      <ul className="todo__list">
        {todos.map(todo => (
          <li
            key={todo.id}
              className="todo__item"
          >
            <Todo todo={todo} />
          </li>
        )}  
      </ul>
    </div>
  );    
}

这个todo app有2个主要的动作,'ADD_TODO', 'TOGGLE_TODO',下面来完成action creators,reducers等

action creators, reducers

action creators

// 产生一个随机的32位字符串
const uid = () => Math.randow().toString(34).slice(2);

const addTodo = (text) => ({
  type: 'ADD_TODO',
  payload: {
    id: uid(),
    text,
    isDone: false
  }
});
const toggleTodo = (id) => ({
  type: 'TOGGLE_TODO',
  payload: id 
});

reducers 和 immutable js

在这里就涉及到数据的处理工作了,通过immutable来完成添加和更新数据。(这里actions比较少,直接将所有的actions.type都用一个reducer处理)

// 使用常用的Map, List集合
import { Map, List } from 'immutable';

# 初始化, 将初始状态变为List集合
const initState = List([]);

// 将数据解构变为immutable形式
List [
  Map { id: 0, isDone: true,  text: 'make components' },
  Map {...},
  Map {...}
  ...
]

const rootReducer = (state = initState, action) => {
  switch (action.type) {
    case 'ADD_TODO':
    // 变为immutable之后,可以直接使用 'push' 来添加到数组
    // 不用担心改变原来的数据
      # 注意先将对象变为Map集合之后再push到 List集合中
      return state.push(Map(action.payload));
    case 'TOGGLE_TODO':
     // 对于更新Map集合中的某个属性,使用immutable中update方法 
     // Map集合 update方法的其中一种形式 update(key, updater)
      # 注意这里使用immutable中的'map'和'get'方法: todo.get('id')  
      return state.map(todo => {
        if (todo.get('id') === action.payload) {
          return todo.update('isDone', isDone => !isDone);
        } else {
          return todo;
        }
      });

    default:
      return state;       
  }
}

然后将逻辑写入纯组件中

const TodoList = ({ todos, toggleTodo, addTodo }) => {
    const onSubmit = (e) => {
      const input = e.target;
      const text = input.value;
      # 判断是否为 enter 键
      const isEnterKey = e.which === 13;
      const isLongEnough = text.length > 0;
      if (isEnterKey && isLongEnough) {
        addTodo(text);
        input.value = '';
      }
    };

    const toggleClick = (id) => () => toggleTodo(id);

    return (
      <div>
        <input 
          type="text"
          placeholder="add a task"
          onKeyDown={onSubmit}
        />
        <ul>
          {todos.map(todo => (
            <li
              # 注意这里需要使用get来获取Map集合中的id
              # 而不能直接的使用todo.id
              key={todo.get('id')}
              onClick={toggleClick(todo.get('id'))}
            >
                # 注意这里要将Map集合转变为普通JS对象
                <Todo todo={todo} />
            </li>
          ))}
        </ul>
      </div>
    )
}

使用react-redux将状态和组件连接起来

import { connect } from 'react-redux';

const mapStateToProps = (state) => ({
  todos: state
});

const mapDispatchToProps = (dispatch) => ({
  addTodo: text => dispatch(addTodo(text)),
  toggleTodo: id => dispatch(toggleTodo(id))
});

// 这相当于
<TodoList 
  todos={state}
  addTodo={text => dispatch(addTodo(text))}
  toggleTodo={id => dispatch(toggleTodo(id))}
/>

// 使用一个容器
const TodoListContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList);

将store通过Provider传递下去

import { createStore } from 'redux';
import { Provider } from 'react-redux';

const store = createStore(rootReducer);

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

完成!

完整代码 jsbin

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容