惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Tenable Blog
WordPress大学
WordPress大学
小众软件
小众软件
Y
Y Combinator Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
大猫的无限游戏
大猫的无限游戏
T
The Exploit Database - CXSecurity.com
Attack and Defense Labs
Attack and Defense Labs
Simon Willison's Weblog
Simon Willison's Weblog
C
CXSECURITY Database RSS Feed - CXSecurity.com
量子位
有赞技术团队
有赞技术团队
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Fortinet All Blogs
S
Schneier on Security
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
Martin Fowler
Martin Fowler
Recent Announcements
Recent Announcements
Stack Overflow Blog
Stack Overflow Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
阮一峰的网络日志
阮一峰的网络日志
G
GRAHAM CLULEY
Spread Privacy
Spread Privacy
F
Full Disclosure
Scott Helme
Scott Helme
GbyAI
GbyAI
N
Netflix TechBlog - Medium
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric
云风的 BLOG
云风的 BLOG
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
Hacker News - Newest:
Hacker News - Newest: "LLM"
Security Latest
Security Latest
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MongoDB | Blog
MongoDB | Blog
The GitHub Blog
The GitHub Blog
The Register - Security
The Register - Security
L
Lohrmann on Cybersecurity
PCI Perspectives
PCI Perspectives
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
D
Docker
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Secure Thoughts
C
Check Point Blog

ZDDHUB

PixelsMeasure 开发第二年总结 PixelsMeasure 开发一年总结 Swift/SwiftUI 踩坑记 为什么说 GPT 利好程序员 ChatGPT 编程实现 Web 数字水印 Web 数字水印探究 Micro Frontends for Mobile URL 加载系统(URL Loading System) Protocol Buffers GraphQL 从 0 到 1 开发一款 IOS 应用 - Swift MV* 软件设计架构 学习一个新技巧需要多久? 不停机数据库迁移 Rspec 如何 mock update 方法更新自己? Rails 使用 mysql2 出现的段错误 使用 Docker-compose 部署 Rails 应用到生产环境 Cocoa troubleshooting 独孤九剑 Dit (0x05) - 终端篇 Gem-based Jekyll theme 开发小记 Miscellaneous 前端手记 TodoMVC 之 Server 篇 前端手记 TodoMVC 之 React 篇 前端手记 TodoMVC 之 CSS 篇 独孤九剑 Dit (0x04) - 测试篇 独孤九剑 Dit (0x03) - 缓存篇 英语小抄 LLDB debug Golang Make mistakes 大牛俱乐部上线啦 独孤九剑 Dit (0x02) - 数据结构篇 独孤九剑 Dit (0x01) - 总决 独孤九剑 Dit (0x00) - 我为什么要做 Dit 零值强制类型转换的使用 终端颜色输出重定向 Go语法简略 - 正则表达式 Makefile Go语法简略 - Duck框架探索 Go语法简略 - 依赖注入 Go语法简略 - web应用框架 Go语法简略 - 反射 Go语法简略 - 面向对象 Go语法简略 - goroutine Go语法简略 - 方法和接口 Go语法简略 - 基础篇 大牛 轻松科研 未来这几年 为 Android Studio 创建图标 Shell Git Vim 金庸答百问 论拖延症 Flex, A fast scanner generator 有理想的人 从虚拟到现实 常用视频转接口 Recognizer configuration on CentOS 整个世界清静了 《Python源码剖析》读书笔记
前端手记 TodoMVC 之 Redux 篇
zddhub · 2016-10-14 · via ZDDHUB

React 将应用程序分解成不同的 component,每个 component 单独完成事件响应或者数据展示。把只负责数据展示的 component 叫做 Presentational Component,易复用。把与业务逻辑/业务处理密切相关的 component 叫做 Container Component,极难复用,通常作为 Presentational Component 的父 component 存在,比如我实现的 TodoMVC 中的 TodoApp

React 很好的处理了 View 层的复用,在数据方面,采用单向流动的方式,减少了前端逻辑的复杂程度。它将数据划分为 props 和 state 两种类型,并强烈建议能用 props 就用 props 类型,在万不得已/无法避免的情况下,才使用 state 数据。这是因为 props 上的数据在向下传递的过程中不可变,而 state 上的数据是可变的,并且它通过 setState 方法异步更新。

在复杂的单页应用中,可变的 state 的数据增多,加上异步更新方式,给开发和测试都带来了困难。对于 React 上的数据处理问题, Facebook 出了一个方案叫 Flux,然而 Redux 走的更远,并且得到了 Flux 作者的认可。Redux 把 state 数据存储在单独的对象 (store) 中, 绑定到顶层的 Container Component 上,使得 state 数据和 React 分离,React component 用到的所有数据都能从 props 上得到。 这一篇就用 Redux 改写我们的 TodoMVC demo。

Redux 三大原则

  • 单一数据源: 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中;
  • State 是只读的: 惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
  • 使用纯函数来执行修改: 为了描述 action 如何改变 state tree ,你需要编写 reducers。

就是这样,现在你应该明白 Redux 是怎么回事了。Redux 将 state 数据限制为只读,只有通过写纯虚函数的 reducers 才能改变,这个应用程序的 state 数据被存储在单一的 object tree 上。

Redux 三个基本概念

  • Action

Action 是把数据从应用层传递到 store 的有效载体,它是 store 数据的唯一来源。Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。Action 仅仅表示某对象发生了什么行为,我们应该尽量减少在 action 中传递的数据。

TodoMVC demo 的 Action:

ADD_TODO REMOVE_TODO COMPLETE_TOOD TRIGGER_ALL_TODOS FILTER_TODOS

异步 API 一般有三个关键时间点可以通知给 reducer:

  1. 请求开始
  2. 请求成功结束
  3. 请求失败

可以用三个不同的 Action 来通知给 reducer,或者用一个 Action,设置不同的 status,到底用哪种完全取决于你。

  • Reducer

Action 只是描述了有事情发生了这一事实,并没有指明应用如何更新 state。而这正是 reducer 要做的事情。reducer 就是一个纯函数,接收当前 state 和 action,返回新的 state。函数形式如下:

(previousState, action) => newState

只要传入参数相同,返回的 newState 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:

  1. 修改传入参数;
  2. 执行有副作用的操作,如 API 请求和路由跳转;
  3. 调用非纯函数,如 Date.now() 或 Math.random()。

记得不要修改 previousState 的值,创建一个新的对象返回给 newState。

  • Store

使用 reducers 来根据 action 更新 state, 存储在 store 中。store 把之前创建的 Action 和 Reducer 联系在一起。store 的职责有:

  1. 持有应用的 state;
  2. 提供 getState() 方法获取 state;
  3. 提供 dispatch(action) 方法更新 state;
  4. 通过 subscribe(listener) 注册监听器;
  5. 通过 subscribe(listener) 返回的函数注销监听器。

有了 reducer 之后,创建 store 只需要一句话 let store = createStore(todoApp)。接下来看看 redux 的数据流吧。

Redux 数据流

Redux 架构使用严格的单向数据流动方式,其生命周期分为以下四步:

  1. 应用调用 store.dispatch(action) 发送 Action
  2. Redux 根据传入的 action 调用对应的 reducer 方法
  3. 根 reducer 把子 reducer 的结果合并成一颗 state 树
  4. Redux store 保存根 reducer 生成的 state 树

得到的 state 树即为当前应用的下一个 state,所有订阅 store.subscribe(listener) 的监听器都将被调用。监听器可以调用 store.getState() 获得当前 state。

Redux + todoMVC

首先,设计我们的 state 树,如下:

{
  todos: {
    isFetching: false,
    didInvalidate: false,
    items: [
      {
        "title": "Start Redux",
        "completed": false,
        "createdAt": "2016-10-18T00:15:50.105Z",
        "updatedAt": "2016-10-20T00:35:04.858Z",
        "id": 1
      },
      {
        "title": "Start TodoMVC",
        "completed": false,
        "createdAt": "2016-10-18T11:20:26.200Z",
        "updatedAt": "2016-10-20T00:35:04.858Z",
        "id": 2
      }
    ]
  },
  filter: 'All'
}

其中,todos 为异步 action,数据来自服务器, isFetching 表示数据的状态,didInvalidate 标记数据是否过期。filter 为 同步 action, 数据来自客户端操作,默认为 ‘All’。

好了,现在开始实现你的异步 TodoMVC Demo 吧, 从文档到实现,还是有些坑,试试跨越吧,我们必须过这一关。我的实现在这里 13a1c3748c7e39f77c04507971b0c13822a6d3a7, 之后有些整理代码的提交,欢迎补充。

Props 数据验证

利用 Redux,应用中的 state 被统一存储在 store 中,只在 container 上通过 connect 的方式,把 state 数据 map 成 props,使得 React 中的 component 上,只有一种 props 数据, React 提供了一个验证 props 数据的方法, 使用 PropTypes。PropTypes 确保上层传给子 compoennt 的 props 数据符合期望。使用了 PropTypes 验证的代码在这里 34324f5405b52abbef36e7991542d5a228c85403

注意,并不是说使用了 Redux 的应用中不能有 state, 对于底层的 component,上层 container 不应该了解其内部结构。

除了数据验证,代码测试同样重要,Action 和 Reducer 很容易撰写测试,略。

和大神作品比较

除了 TodoMVC 自带的 demo 外, Redux 项目的例子里也有两个 todoMVC 的例子, 我都看了哦,不过像我这种把 TodoMVC 的数据存储在服务器端的奇葩做法,还真不多见。

参考资料

如果你喜欢这篇文章,欢迎赞赏作者以示鼓励