美文网首页
彻底捋顺redux

彻底捋顺redux

作者: forever_提拉米苏 | 来源:发表于2021-01-25 16:39 被阅读0次

仔细算来,redux用了也有一年多了,但一直是用的时候捡起来,不用又忘了的情况,处在似懂非懂的阶段。这篇文章用来对redux做一个总结,彻底搞懂redux。


Redux是JavaScript状态容器,提供可预测化的状态管理。redux提出的目的是为了解决大型的复杂应用中组件之间的通信困难、代码结构混乱等问题。具体来说就是以下几种场景:
就使用场景来说,

  • 用户的使用方式复杂
  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 多个用户之间可以协作
  • 与服务器大量交互,或者使用了WebSocket
  • View要从多个来源获取数据

就组件常见来说,

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

发生上面情况时,如果不使用 Redux 或者其他状态管理工具,不按照一定规律处理状态的读写,代码很快就会变成一团乱麻。你需要一种机制,可以在同一个地方查询状态、改变状态、传播状态的变化。

开始之前先来了解几个概念

Redux 由以下组件组成:
  • Action,这是一个用来描述发生了什么事情的对象。
  • Reducer,接收action并更新Store。
  • Store,整个程序的状态/对象树保存在Store中。
  • View,只显示 Store 提供的数据。
Redux有三大原则
  • 单一数据源store:store是整个应用的数据存储中心(store tree),集中大部分页面需要的状态数据;
  • state是只读的,所以需要view触发action去更新store;
  • 使用纯函数Reducer执行state更新。
image.png

下面开始逐一介绍

  1. Store
    Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。Redux 提供createStore这个函数,用来生成 Store。store提供getState方法获取所有的state
import { createStore } from 'redux';
const store = createStore(reducer);

const state = store.getState();
  1. Action
    上面说过state是只读的,State 的变化会导致 View 的变化。但是用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
const action = {
  type: 'ADD',
  payload: 1
};

Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store。
定义好Action了,怎么发出呢?store.dispatch()是 View 发出 Action 的唯一方法。

import { createStore } from 'redux';
const store = createStore(reducer);

store.dispatch(action);
  1. reducer
    Reducer 是一个纯函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
// 这里reducer也可以进行拆分,放到单独一个文件中
import { createStore } from 'redux';

const defaultState = 0;
const increaseReducer = (state = defaultState, action) => {
  switch (action.type) {
    case 'ADD':
      return state + action.payload;
    default: 
      return state;
  }
}
const store = createStore(increaseReducer);

上面代码中,由于store.dispatch方法会触发 Reducer 的自动执行,Store 需要知道 Reducer 函数,做法就是在生成 Store 的时候,将 Reducer 传入createStore方法。
createStore接受 Reducer 作为参数,生成一个新的 Store。以后每当store.dispatch发送过来一个新的 Action,就会自动调用 Reducer,得到新的 State。

Reducer 函数最重要的特征就是它必须是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。纯函数是函数式编程的概念,必须遵守一些约束:

  • 不得改写参数
  • 不能调用系统 I/O 的API
  • 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果

ps: reducer拆分
试想一下,在一个大型应用中 State 必然十分庞大,导致 Reducer 函数也十分庞大。在上面的例子中我们提到reducer也可以进行拆分,放在一个文件里面,然后统一引入。Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。

import { combineReducers } from 'redux'
import increase from './increase'
import decrease from './decrease'

const reducer = combineReducers({
  value: increase,
  decrease  // 这种写法有一个前提,就是 State 的属性名必须与子 Reducer 同名。否则就用上面这种写法
})
export default reducer;

  1. React-Redux 的用法
    React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。

UI 组件有以下几个特征:

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

容器组件的特征如下:

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API
connect

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

import { connect } from 'react-redux'
import mapStateToProps from ''
import mapDispatchToProps  from ''

const App= connect(
  mapStateToProps,   // value 来自这里
  mapDispatchToProps   // onIncreaseClick 来自这里
)(Counter)

class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>
    )
  }
}

export default App

上面代码中,Counter是 UI 组件,App就是由 React-Redux 通过connect方法自动生成的容器组件。

mapStateToProps

mapStateToProps是一个函数。它的作用就是像它的名字那样,建立一个从state对象(外部的)到props对象(UI 组件的)的映射关系。mapStateToProps执行后返回一个对象,里面的每一个键值对就是一个映射。

const mapStateToProps = state => {
  return {
    value: state.value
  }
}

mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。

mapDispatchToProps

mapDispatchToProps是connect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象。

const mapDispatchToProps = dispatch=> {
  return {
    onIncreaseClick: () => {
      dispatch({
        type: 'ADD',
        payload: 1
      });
    }
  };
}
<Provider> 组件

connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。如果一级级将state传下去就很麻烦,React-Redux 提供Provider组件,可以让容器组件拿到state。

import { Provider } from 'react-redux'
import { createStore } from 'redux'
import reducer from './reducers'
import App from './app'

let store = createStore(reducer);

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

上面代码中,Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了

redux可以使代码结构更加规范,代码可读性更强。因为React提出将展示组件/UI组件(业务逻辑)与容器组件(数据源)分离的思想,所以降低了React 与Redux之间的耦合度。


为什么我能够看得更远,那是因为我站在巨人的肩上,以上内容来源:
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html

相关文章

  • 彻底捋顺redux

    仔细算来,redux用了也有一年多了,但一直是用的时候捡起来,不用又忘了的情况,处在似懂非懂的阶段。这篇文章用来对...

  • 捋顺

    很开心,今日终于找到了捋顺剧情的方法。 剧情顺了,心情也就顺了,不卡文了,不纠结了,也不用薅头发了,连世界都跟着美...

  • 顺捋

    随处可见的核酸棚子,三步一岗,五步一哨,大有生产、抗疫两不误之感。人还是好热闹的。我也是憋了许久,思虑再来的。比起...

  • 捋顺纠结

    昨天晚上,一打开手机就看到筷儿的班级群热闹非凡,原来是要订校服了,看到家长们大多都订的120,我想碗儿之前...

  • 顺毛捋

    不论男女老少,都喜欢顺毛捋,喜欢听好听的话,不喜被指责和谩骂。 孩子喜欢顺毛捋。写作业时,看到她坐姿不正确,如果你...

  • 捋顺,加油

    今天定好了计划,买了笔袋和手表还有衣服,感觉做了很多事情,又认真工作了一天,今天工作状态也很棒。 用OKR管理我的...

  • 「搬运」16-08-16

    捋顺不易

  • 如何捋顺思路?

    新换的工作,样样棘手,这个不会那个也不懂,想快点跑通整个流程又觉得各项基本功不扎实,陷入了深深的矛盾和 纠结...

  • 思路需要捋顺

    加了一天班,有点心慌,有顺利发展的,也有踯躅不前的,怎样发展,我要花多长时间去做这个事情,是我需要考虑清楚了。 我...

  • 如何捋顺关系

    半夜,被孩子气的从困意绵绵到胸闷气短。从孩子的学舞蹈不认真,贪玩,爱买东西开始,到晚上睡觉开大灯,不好好睡,又跑到...

网友评论

      本文标题:彻底捋顺redux

      本文链接:https://www.haomeiwen.com/subject/qnjezktx.html