0%

Redux 入门教程(三):React-Redux 的用法

Redux 入门教程(三):React-Redux 的用法

React-Redux 是 Redux 的 React 绑定库,它可以让你的 React 组件从 Redux store 中读取数据,并且向 store 分发 actions 来更新数据。

一、UI 组件和容器组件

React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。

UI 组件

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用 this.state
  • 所有数据都由参数(props)提供
  • 不使用 Redux 的 API

容器组件

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API

二、connect 方法

React-Redux 提供 connect 方法,用于从 UI 组件生成容器组件。

1
2
3
4
5
6
import { connect } from 'react-redx';

const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList);

1. mapStateToProps

1
2
3
4
5
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
};
};

2. mapDispatchToProps

1
2
3
4
5
6
7
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id));
}
};
};

三、Provider 组件

Provider 组件可以让容器组件拿到 state

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import todoApp from './reducers';
import App from './components/App';

let store = createStore(todoApp);

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

四、实例:Todo 应用

1. 定义 Action Types

1
2
3
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';

2. 创建 Action Creators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export const addTodo = (text) => ({
type: ADD_TODO,
text
});

export const toggleTodo = (id) => ({
type: TOGGLE_TODO,
id
});

export const setVisibilityFilter = (filter) => ({
type: SET_VISIBILITY_FILTER,
filter
});

3. 实现 Reducer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const initialState = {
visibilityFilter: 'SHOW_ALL',
todos: []
};

function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
});
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
});
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: state.todos.map((todo, index) => {
if (index === action.id) {
return Object.assign({}, todo, {
completed: !todo.completed
});
}
return todo;
})
});
default:
return state;
}
}

4. 创建容器组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
};
};

const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id));
}
};
};

const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList);

五、最佳实践

  1. 组件拆分

    • 将 UI 组件和容器组件分开
    • 保持组件的单一职责
    • 适当使用高阶组件
  2. 性能优化

    • 使用 shouldComponentUpdateReact.memo
    • 避免不必要的重渲染
    • 合理使用 useSelectoruseDispatch
  3. 代码组织

    • 按功能模块组织代码
    • 使用常量定义 action types
    • 保持 reducer 的纯函数特性
  4. 调试技巧

    • 使用 Redux DevTools
    • 添加适当的日志
    • 使用 TypeScript 增加类型安全