ReactJS101 项目:Redux 实战入门教程

ReactJS101 项目:Redux 实战入门教程

reactjs101 kdchang/reactjs101: 是一个关于 ReactJS 的前端开发教程项目。适合对前端开发有兴趣的人,特别是想学习 ReactJS 框架的人。特点是从基础概念和示例代码入手,逐步深入到 ReactJS 的各种高级特性,具有较强的实践性和指导性。 reactjs101 项目地址: https://gitcode.com/gh_mirrors/re/reactjs101

引言

在现代前端开发中,状态管理一直是构建复杂应用的关键挑战。Redux 作为 React 生态中最流行的状态管理解决方案之一,通过单向数据流和不可变状态等核心概念,为开发者提供了可预测的状态管理方案。本文将基于 ReactJS101 项目中的 Redux 实战示例,带您一步步构建一个完整的 Todo 应用,深入理解 Redux 的核心工作流程。

Redux 核心概念回顾

在开始实战之前,让我们快速回顾 Redux 的几个核心概念:

  1. Store:应用的单一数据源,存储整个应用的状态
  2. Action:描述发生了什么的对象,是改变状态的唯一途径
  3. Reducer:纯函数,接收旧状态和 action,返回新状态
  4. Middleware:提供第三方插件的扩展点,用于处理异步等操作

项目初始化与配置

1. 创建项目结构

我们首先需要建立合理的项目目录结构,这是保持代码可维护性的基础:

src/
├── actions/        # Redux action 定义
├── components/     # 展示组件
├── containers/     # 容器组件
├── constants/      # 常量定义
├── reducers/       # Redux reducer
├── store/          # Redux store 配置
└── index.js        # 应用入口文件

2. 安装依赖

项目需要安装以下核心依赖:

  • react/react-dom:React 核心库
  • redux/react-redux:Redux 及其 React 绑定
  • immutable:不可变数据结构
  • redux-actions:简化 action 创建
  • redux-immutable:支持 immutable 的 combineReducers

开发依赖包括 Babel、ESLint、Webpack 等构建工具。

构建 Redux 核心部分

1. 定义 Action Types

constants/actionTypes.js 中定义应用需要的 action 类型:

export const CREATE_TODO = 'CREATE_TODO';
export const DELETE_TODO = 'DELETE_TODO';
export const CHANGE_TEXT = 'CHANGE_TEXT';

2. 创建 Actions

使用 redux-actions 创建 action creators:

import { createAction } from 'redux-actions';
import { CREATE_TODO, DELETE_TODO, CHANGE_TEXT } from '../constants/actionTypes';

export const createTodo = createAction(CREATE_TODO);
export const deleteTodo = createAction(DELETE_TODO);
export const changeText = createAction(CHANGE_TEXT);

3. 设计初始状态

使用 Immutable.js 定义初始状态结构:

import Immutable from 'immutable';

export const TodoState = Immutable.fromJS({
  todos: [],
  todo: {
    id: '',
    text: '',
    updatedAt: '',
    completed: false
  }
});

4. 实现 Reducers

使用 handleActions 简化 reducer 编写:

import { handleActions } from 'redux-actions';
import { TodoState } from '../../constants/models';

const todoReducers = handleActions({
  CREATE_TODO: (state) => {
    let todos = state.get('todos').push(state.get('todo'));
    return state.set('todos', todos);
  },
  DELETE_TODO: (state, { payload }) => (
    state.set('todos', state.get('todos').splice(payload.index, 1))
  ),
  CHANGE_TEXT: (state, { payload }) => (
    state.merge({ 'todo': payload })
  )
}, TodoState);

5. 配置 Store

创建并配置 Redux store:

import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import Immutable from 'immutable';
import rootReducer from '../reducers';

const initialState = Immutable.Map();

export default createStore(
  rootReducer,
  initialState,
  applyMiddleware(createLogger({ stateTransformer: state => state.toJS() }))
);

构建 React 组件

1. 容器组件与展示组件

遵循容器组件与展示组件分离的原则:

  • 容器组件:连接到 Redux store,管理数据和行为
  • 展示组件:只负责 UI 呈现,不感知 Redux

2. TodoHeader 组件

展示组件只关注 UI 呈现:

const TodoHeader = ({
  onChangeText,
  onCreateTodo,
  todo,
}) => (
  <div>
    <h1>TodoHeader</h1>
    <input type="text" value={todo.get('text')} onChange={onChangeText} />
    <button onClick={onCreateTodo}>送出</button>
  </div>
);

对应的容器组件负责连接 Redux:

const mapStateToProps = (state) => ({
  todo: state.getIn(['todo', 'todo'])
});

const mapDispatchToProps = (dispatch) => ({
  onChangeText: (event) => (
    dispatch(changeText({ text: event.target.value }))
  ),
  onCreateTodo: () => {
    dispatch(createTodo());
    dispatch(changeText({ text: '' }));
  }
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoHeader);

3. TodoList 组件

展示组件:

const TodoList = ({
  todos,
  onDeleteTodo,
}) => (
  <div>
    <ul>
    {todos.map((todo, index) => (
      <li key={index}>
        {todo.get('text')}
        <button onClick={onDeleteTodo(index)}>X</button>
      </li>
    )).toJS()}
    </ul>
  </div>
);

容器组件:

const mapStateToProps = (state) => ({
  todos: state.getIn(['todo', 'todos'])
});

const mapDispatchToProps = (dispatch) => ({
  onDeleteTodo: (index) => () => (
    dispatch(deleteTodo({ index }))
  )
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList);

应用入口

最后在应用入口使用 Provider 提供 store:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Main from './components/Main';
import store from './store';

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

开发技巧与最佳实践

  1. Immutable.js 使用

    • 始终使用 get() 方法获取值
    • 修改状态时使用 set()、merge() 等方法返回新对象
    • 在组件渲染前使用 toJS() 转换数组
  2. Redux 调试

    • 使用 redux-logger 中间件记录状态变化
    • 结合 Redux DevTools 进行时间旅行调试
  3. 性能优化

    • 合理划分 reducer,避免不必要的重新渲染
    • 使用 reselect 创建记忆化的选择器

总结

通过这个 Todo 应用的实战开发,我们完整地实践了 Redux 的核心工作流程:

  1. 用户交互触发 action
  2. Reducer 根据 action 类型处理状态变更
  3. 新状态通过 React-Redux 传递给组件
  4. 组件根据新状态重新渲染

这种单向数据流模式使得状态变化变得可预测和易于调试。虽然 Redux 的学习曲线相对陡峭,但一旦掌握其核心概念,就能极大地提高大型应用的状态管理能力。

在后续开发中,可以考虑引入 Redux Saga 或 Redux Thunk 处理异步操作,使用 Normalizr 规范化状态结构,以及实施更细致的性能优化策略。

reactjs101 kdchang/reactjs101: 是一个关于 ReactJS 的前端开发教程项目。适合对前端开发有兴趣的人,特别是想学习 ReactJS 框架的人。特点是从基础概念和示例代码入手,逐步深入到 ReactJS 的各种高级特性,具有较强的实践性和指导性。 reactjs101 项目地址: https://gitcode.com/gh_mirrors/re/reactjs101

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翟舟琴Jacob

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值