React-Redux 基础教程:从零构建待办事项应用
react-redux 项目地址: https://gitcode.com/gh_mirrors/rea/react-redux
前言
在现代前端开发中,状态管理是一个至关重要的环节。React-Redux 作为 React 生态中最流行的状态管理解决方案之一,为开发者提供了一套优雅的模式来管理应用状态。本文将带你从零开始,通过构建一个完整的待办事项(Todo)应用,深入理解 React-Redux 的核心概念和使用方法。
应用架构概览
我们的待办事项应用将包含以下几个核心部分:
- UI组件层:负责渲染界面和处理用户交互
- Redux Store:集中管理应用状态
- 连接层:使用 React-Redux 将组件与Store连接起来
UI组件结构
让我们先了解应用的UI组件结构:
TodoApp
:应用的根组件,包含所有其他子组件AddTodo
:添加新待办事项的输入框和按钮TodoList
:显示待办事项列表Todo
:单个待办事项的展示组件VisibilityFilters
:过滤选项组件(全部/已完成/未完成)
Redux Store设计
Redux部分遵循了最佳实践模式:
-
状态结构:
todos
:包含byIds
(按ID组织的待办事项)和allIds
(所有ID的数组)visibilityFilters
:当前选中的过滤条件
-
Action创建函数:
addTodo(content)
:添加新待办事项toggleTodo(id)
:切换待办事项完成状态setFilter(filter)
:设置过滤条件
-
Reducer函数:
- 处理上述action,更新对应的状态
连接React与Redux
第一步:提供Store
要让整个React应用能够访问Redux store,我们需要在最外层使用Provider
组件:
import { Provider } from 'react-redux';
import store from './redux/store';
ReactDOM.render(
<Provider store={store}>
<TodoApp />
</Provider>,
document.getElementById('root')
);
Provider
使用了React的Context API,使得store可以被所有子组件访问。
第二步:连接组件
React-Redux提供了connect
函数来连接组件与store。connect
接受两个主要参数:
mapStateToProps
:定义如何从store中提取组件需要的数据mapDispatchToProps
:定义哪些action创建函数需要注入到组件props中
连接AddTodo组件
AddTodo
组件需要能够添加新的待办事项:
import { connect } from 'react-redux';
import { addTodo } from '../redux/actions';
class AddTodo extends React.Component {
// ...组件实现
}
export default connect(
null, // 不需要从store读取数据
{ addTodo } // 注入addTodo action
)(AddTodo);
在组件中,我们可以直接通过this.props.addTodo
来调用action。
连接TodoList组件
TodoList
需要显示待办事项列表,因此需要从store读取数据:
import { connect } from 'react-redux';
import { getTodos } from '../redux/selectors';
const TodoList = ({ todos }) => (
// ...渲染待办事项列表
);
const mapStateToProps = state => ({
todos: getTodos(state)
});
export default connect(mapStateToProps)(TodoList);
这里我们使用了selector函数getTodos
来从store中提取并处理数据。使用selector的好处是可以将数据转换逻辑与组件分离,便于维护和重用。
连接Todo组件
单个待办事项组件需要能够切换完成状态:
import { connect } from 'react-redux';
import { toggleTodo } from '../redux/actions';
const Todo = ({ id, content, completed, toggleTodo }) => (
// ...渲染单个待办事项
);
export default connect(
null,
{ toggleTodo }
)(Todo);
连接VisibilityFilters组件
过滤组件需要知道当前选中的过滤条件,并能改变它:
import { connect } from 'react-redux';
import { setFilter } from '../redux/actions';
const VisibilityFilters = ({ activeFilter, setFilter }) => (
// ...渲染过滤选项
);
const mapStateToProps = state => ({
activeFilter: state.visibilityFilter
});
export default connect(
mapStateToProps,
{ setFilter }
)(VisibilityFilters);
高级技巧:按条件过滤待办事项
为了实现按条件(全部/已完成/未完成)过滤待办事项,我们需要增强selector的功能:
export const getTodosByVisibilityFilter = (store, visibilityFilter) => {
const allTodos = getTodos(store);
switch (visibilityFilter) {
case 'COMPLETED':
return allTodos.filter(todo => todo.completed);
case 'INCOMPLETE':
return allTodos.filter(todo => !todo.completed);
default:
return allTodos;
}
};
然后在TodoList组件中使用这个selector:
const mapStateToProps = state => {
const { visibilityFilter } = state;
const todos = getTodosByVisibilityFilter(state, visibilityFilter);
return { todos };
};
connect函数的四种常见用法
在实际开发中,connect
函数有几种常见的使用模式:
-
不订阅store,不注入action:
connect()(Component)
- 组件不会因store变化而重新渲染
- 通过props.dispatch手动dispatch action
-
订阅store,不注入action:
connect(mapStateToProps)(Component)
- 组件会订阅mapStateToProps返回的数据变化
- 通过props.dispatch手动dispatch action
-
不订阅store,注入action:
connect(null, mapDispatchToProps)(Component)
- 组件不会因store变化而重新渲染
- action creators会作为props注入并自动dispatch
-
订阅store并注入action:
connect(mapStateToProps, mapDispatchToProps)(Component)
- 组件会订阅mapStateToProps返回的数据变化
- action creators会作为props注入并自动dispatch
性能优化建议
-
使用记忆化的selector:对于复杂的数据转换,使用像Reselect这样的库创建记忆化selector,避免不必要的计算。
-
精细化mapStateToProps:只订阅组件真正需要的数据,减少不必要的重新渲染。
-
避免在mapStateToProps中创建新对象:如果返回的对象总是新的,即使内容没变也会导致组件重新渲染。
总结
通过这个待办事项应用的开发,我们学习了React-Redux的核心概念:
- 使用
Provider
使store对整个应用可用 - 使用
connect
函数连接组件与store - 通过
mapStateToProps
订阅store数据 - 通过
mapDispatchToProps
注入action creators - 使用selector函数组织和转换store数据
React-Redux的这种模式使得状态管理变得清晰可维护,组件可以专注于UI渲染,而将状态管理交给Redux处理。这种关注点分离是构建大型可维护React应用的关键。
react-redux 项目地址: https://gitcode.com/gh_mirrors/rea/react-redux
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考