彻底捋顺redux

2021-01-25  本文已影响0人  forever_提拉米苏

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


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

就组件常见来说,

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

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

Redux 由以下组件组成:
Redux有三大原则
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 函数最重要的特征就是它必须是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。纯函数是函数式编程的概念,必须遵守一些约束:

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 组件有以下几个特征:

容器组件的特征如下:

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

上一篇下一篇

猜你喜欢

热点阅读