一种简化 Redux 的思路

简介:

动机

我们热爱 React 和 Redux。但是,Redux 中有太多的样板文件,需要很多的重复劳动,这一点令人沮丧;更别提在实际的 React 应用中,还要集成 react-router 的路由功能了。

一个典型的 React/Redux 应用看起来像下面这样:

actions.js

export const ADD_TODO = 'todos/add'
export const COMPLETE_TODO = 'todos/complete'

export function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

export function completeTodo(id) {
  return {
    type: COMPLETE_TODO,
    id
  }
}

reducers.js

import { ADD_TODO, COMPLETE_TODO } from './actions'

let nextId = 0

export default function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [...state, {text: action.text, id: nextId++}]
    case COMPLETE_TODO:
      return state.map(todo => {
        if (todo.id === action.id) todo.completed = true
        return todo
      })
    default:
      return state
  }
}

Todos.js

import { addTodo, completeTodo } from './actions'

// ...

// 在某个事件处理函数中
dispatch(addTodo('a new todo'))

// 在另一个事件处理函数中
dispatch(completeTodo(42))

看起来是不是有点繁冗?这还是没考虑 异步 action 的情况呢。如果要处理异步 action,还需要引入 middleware(比如 redux-thunk 或者 redux-saga),那么代码就更繁琐了。

在一个接口中定义 action/reducer?

Todos.js

import mirror, { actions } from 'mirrorx'

let nextId = 0

mirror.model({
  name: 'todos',
  initialState: [],
  reducers: {
    add(state, text) {
      return [...state, {text, id: nextId++}]
    },
    complete(state, id) {
      return state.map(todo => {
        if (todo.id === id) todo.completed = true
        return todo
      })
    }
  }
})

// ...

// 在某个事件处理函数中
actions.todos.add('a new todo')

// 在另一个事件处理函数中
actions.todos.complete(42)

是不是就简单很多了?只需一个方法,即可定义所有的 actionreducer(以及 异步 action)。

而且,这行代码:

actions.todos.add('a new todo')

完全等同于这行代码:

dispatch({
  type: 'todos/add',
  text: 'a new todo'
})

完全不用关心具体的 action type,不用写大量的重复代码。简洁,高效

异步 action

上述代码示例仅仅针对同步 action。那 异步 action 怎么处理呢?

mirror.model({
  // 省略前述代码
  effects: {
    async addAsync(data, getState) {
      const res = await Promise.resolve(data)
      // 调用 `actions` 上的方法 dispatch 一个同步 action
      actions.todos.add(res)
    }
  }
})

没错,这样就定义了一个异步 action。上述代码的效果等同于如下代码:

actions.todos.addSync = (data, getState) => {
  return dispatch({
    type: 'todos/addAsync',
    data
  })
}

调用 actions.todos.addSync 方法,则会 dispatch 一个 type 为 todos/addAsync 的 action。

当然,处理这样的 action,必须要借助于 middleware。不过实现这样一个 middleware 也非常简单,开发者只管定义 action/reducer,然后简单地调用一个函数就行了。

总结

既然是对现有开发模式做封装和简化,那么要秉承的一个原则应该是,在尽可能地避免发明新的概念,并保持现有开发模式的前提下,减少重复劳动,提高开发效率。

只提供极少数的新 API,其余的都借用 React/Redux/react-router 已有的接口,针对其做封装和强化。

也就是说,不去“颠覆” React/Redux 开发流,只是简化了接口调用,省去样板代码:

针对上面描述的思路,初步完成了一个“框架”,Mirror

目录
相关文章
|
人工智能 自然语言处理 测试技术
Claude 3非常厉害,但是国内用不上怎么办?
【2月更文挑战第16天】Claude 3非常厉害,但是国内用不上怎么办?
4652 1
Claude 3非常厉害,但是国内用不上怎么办?
|
6月前
|
人工智能 并行计算 测试技术
Claude 3.7登顶webdev榜首,国内怎么使用Claude 3.7
Claude 3.7 登顶 Webdev 榜首,Claude 3.7 Sonnet 以 1363.7 分的竞技场评分位列榜首,远超第二名。相比前代,它在数学与编码能力上提升显著,尤其在代理编码测试中准确率达 62.3%,工具交互测试中达 81.2% 的 SOTA 表现。支持 128k Token 输入,上下文处理能力提升 16 倍,并引入扩展思考模式,大幅提升复杂任务解决效率。 Claude 3.7 是 Anthropic 推出的新一代 LLM,具备卓越的推理和编程能力。国内用户可参考特定指南注册使用。
992 14
Claude 3.7登顶webdev榜首,国内怎么使用Claude 3.7
|
10月前
|
开发框架 前端开发 JavaScript
React 框架的优点和缺点是什么?
React框架作为当前主流的前端开发框架之一,具有诸多优点,同时也存在一些缺点
|
7月前
|
Ubuntu API 网络虚拟化
ubuntu22 编译安装docker,和docker容器方式安装 deepseek
本脚本适用于Ubuntu 22.04,主要功能包括编译安装Docker和安装DeepSeek模型。首先通过Apt源配置安装Docker,确保网络稳定(建议使用VPN)。接着下载并配置Docker二进制文件,创建Docker用户组并设置守护进程。随后拉取Debian 12镜像,安装系统必备工具,配置Ollama模型管理器,并最终部署和运行DeepSeek模型,提供API接口进行交互测试。
946 15
|
SQL Oracle 安全
Oracle11g更改数据库名(详细教程)
Oracle11g更改数据库名(详细教程)
533 1
|
并行计算 PyTorch 算法框架/工具
PyTorch 2.2 中文官方教程(十七)(4)
PyTorch 2.2 中文官方教程(十七)
481 2
PyTorch 2.2 中文官方教程(十七)(4)
|
消息中间件 Java 关系型数据库
【二十】springboot整合ElasticSearch实战(万字篇)
【二十】springboot整合ElasticSearch实战(万字篇)
2913 47
|
前端开发
z-index失效的几种情况,父标签position属性为relative的时候,详解
z-index失效的几种情况,父标签position属性为relative的时候,详解
|
安全 Windows
简单快速诊断Windows服务器是否中毒或被入侵
Windows 系统中毒或被入侵后,可能会导致系统报错、系统进程 CPU 或内存使用异常、无法远程等诸多问题。遇到这类问题后往往都比较急躁,不知如何下手,今天技术专家五贤来教大家如何诊断你的服务器是否有病毒?
|
数据建模 数据库
E-R图总结规范
E-R图总结规范
2197 0