3月例会分享

迫于需要在周例会上分享 redux , 整理一下相关内容。

恩,按写好的念都没能做到,大脑里一片空白,loser +1

为什么需要状态管理

日常开发 webapp 中,需要模拟 头部的导航,当页面间跳转,需要传递参数时,往往需要携带大量的参数往来于路由跳转之间,这样会导致,history 的紊乱.

我们想实现页面只能按指定的顺序前进或后退,使用 push 前进, goBack 后退, 那对于页面间的参数逻辑传递,就需要一个额外的状态管理。

可以用 本地存储 的方式进行状态管理,通常情况下,这完全可以满足需求。

但遇到这种情况:页面中有多个组件,并且共享同一个经常会变更的状态,如果还是使用 本地存储, 就需要多做一些组件间通信,比如 状态提升 状态改变向上派发事件 等等一系列跨组件操作。这时候,我们可以引入 redux

在 tripH5 的 coupon 页面有注释,用于例会中举例。关于 goback 的爽

关于 redux

Redux is a predictable state container for JavaScript apps.

可预测状态的容器 只有 2kb.

redux 借鉴了函数式编程的思想,采用了 单向数据流 理念,为实现对数据状态的管理封装提供了不同的方法,并规定了我们进行管理的模式。以此来达到数据 可预测,可追溯

redux 关键字

redux store getState subscribe dispatch reducer

开发者预先定义 reduceraction 函数,在恰当的时候派发 action,即 dispatch(action),如果所编写的 reducer 函数没有问题,那么在正常更新状态后可以通过 store.subscribe 注册更新后的回调

reducer 要是一个纯函数

redux 设计哲学

  1. 数据来源单一 store 是唯一的 这区别于 flux
  2. state 是只读的,不能直接修改它
  3. 使用 reducer 函数来接收 action
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
37
38
39
40
41
42
43
import { createStore } from 'redux'

/**
* This is a reducer, a pure function with (state, action) => state signature.
* It describes how an action transforms the state into the next state.
*
* The shape of the state is up to you: it can be a primitive, an array, an object,
* or even an Immutable.js data structure. The only important part is that you should
* not mutate the state object, but return a new object if the state changes.
*
* In this example, we use a `switch` statement and strings, but you can use a helper that
* follows a different convention (such as function maps) if it makes sense for your
* project.
*/

function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

// Create a Redux store holding the state of your app.
// Its API is { subscribe, dispatch, getState }.
let store = createStore(counter)

// You can use subscribe() to update the UI in response to state changes.
// Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly.
// However it can also be handy to persist the current state in the localStorage.
store.subscribe(() => console.log(store.getState()))

// The only way to mutate the internal state is to dispatch an action.
// The actions can be serialized, logged or stored and later replayed.
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })
// 1

redux 不是必须的

人们痛苦地抱怨 Redux, React, FP, 不可变数据和一些别的东西,但我理解他们。那些不需要一系列代码来更新应用状态的方法自然比使用 Redux 更为简单。这说的没错,设计上也是如此。

Redux 提供了一种权衡。它要求你:

  • 1.用简单的对象和数组来描述应用状态.
  • 2.用简单对象来描述应用中的变更.
  • 3.用纯函数来描述处理变更的逻辑.
  • 4.可对状态改变检测,有历史记录.
  • 5.状态的改变,入口只有 reducer 这一个地方,定位错误十分迅速.

无论是不是 React 应用,这些限制都不是创建一个应用所必须的。事实上,这些都是非常强的约束,在把它们加入应用之前,你应当慎重考虑。

ps: 死板,模式代码太多,影响代码编写体验。

中间件

redux 提供了一套中间件机制,使开发者可以在派发任何一个 action 和执行 reducer 这两步之间,添加自定义扩展功能

react-redux

对 redux 进行了封装,使其可以在 react 中自行感知变化

明确 2 个重要概念: 容器组件展示组件

容器组件是指数据状态和逻辑的容器。 展示组件只负责根据接收的数据展示页面。

connect 的核心是将开发者定义的组件,封装转换成容器组件。

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
// Provider
import React from 'react'
import ReactDOM from 'react-dom'

import { Provider } from 'react-redux'
import store from './store'

import App from './App'

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

// connect
import { connect } from 'react-redux'
import { increment, decrement, reset } from './actionCreators'

// const Counter = ...;

const mapStateToProps = (state /*, ownProps*/) => {
return {
counter: state.counter
}
}

const mapDispatchToProps = { increment, decrement, reset }

export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter)

ssr 服务端渲染 同构

之前看 bili 首页,刷新页面发现有一部分仿佛没有销毁一样,直接就出现在了页面上,当时很惊讶,现在发现,应该是因为,首页是服务端渲染,采用的是流的方式。渐进式渲染,减少了 TTFB 时间

16 版本提供了 renderToNodeStreamrenderToStaticNodeStream 方法。

renderToNodeStream 方法持续产生字节流,返回 Readable stream. 最终通过流的形式返回 html 字符串。

原来是 res.send() 流的形式就是 res.write()

静态页面更适合 renderToStaticNodeStream。交互多的更适合 renderToNodeStream

TTFB(Time To First Byte)

指从浏览器发起最初的网络请求,到从服务器接收到第一个字节的时间,它包含了 TCP 连接时间,发送 HTTP 请求的时间和获得响应消息的第一个字节的时间。

DOMContentLoaded 是初始的 HTML 解析完成后调用的钩子 load 是所有资源加载完毕的钩子
如果 html 中包含脚本,则脚本会阻塞 html,加载完会继续解析 html。这也是 js 文件放到 body 最下面的原因之一

next.js ssr 框架

零配置,但可以选择定制化配置。

pages 目录下可以放页面级组件,会自动映射成一个基于服务器的路由

更好的选择

dva
对 react-redux 的一些常用插件进行了封装,提供了新的 api 好处是全面

mobx
不依赖 react diff 更颗粒化地感知变化,提供了 计算属性、reactions 思想与 vue 同出一辙。
虽然相对比较复杂,但理解之后,使用体验很棒。

redux demo

如何从头开始组装一个基本的 crud 应用程序文章地址
代码地址

分享到: