Redux 和 React-Redux

347 阅读2分钟

1. Redux

1.1 store

Store 就是把它们联系到一起的对象。Store 有以下职责:

  • 维持应用的 state;
  • 获取:getState() 方法获取当前的 state 树。
  • 更新:dispatch(action) 方法更新 state。这是触发 state 变化的惟一途径;
  • 监听:subscribe(listener) 注册监听器,返回的函数注销监听器。
import { createStore } from 'redux';
const store = createStore(reducer);

1.2 Reducer 函数

Reducers 指定了应用状态的变化如何响应 actions 并发送到 store。reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。

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

1.3 Action 函数

Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源,通过 store.dispatch() 将 action 传到 store。

{ type: 'INCREMENT' }

1.4 Example

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import Counter from './components/Counter'
import counter from './reducers'

const store = createStore(counter)
ReactDOM.render(
  <Counter
    value={store.getState()}
    onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
    onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
  />,
  document.getElementById('root')
)
store.subscribe(render)

Counter.js

import React, { Component } from 'react'

class Counter extends Component {
  constructor(props) {
    super(props)
  }

  incrementIfOdd = () => {
    if (this.props.value % 2 !== 0) {
      this.props.onIncrement()
    }
  }

  incrementAsync = () => {
    setTimeout(this.props.onIncrement, 1000)
  }

  render() {
    const { value, onIncrement, onDecrement } = this.props
    return (
      <>
        Clicked: {value} times
        <button onClick={onIncrement}>+</button>
        <button onClick={onDecrement}>-</button>
        <button onClick={this.incrementIfOdd}>Increment if odd</button>
        <button onClick={this.incrementAsync}>Increment async</button>
      </>
    )
  }
}

export default Counter

reducers/index.js

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

2. React-Redux

2.1 Provider 标签

<Provider store> 使所有层级中的 connect() 方法都能够获得 Redux store。

<Provider store={store}>
  <App />
</Provider>

2.2 connect 函数

连接 React 组件与 Redux store,返回一个新的已与 Redux store 连接的组件类。

connect([mapStateToProps], [mapDispatchToProps])(App)

- mapStateToProps
负责输入逻辑,将state映射到 UI 组件的参数

- mapDispatchToProps
负责输出逻辑,将用户对 UI 组件的操作映射成 Action

2.3 Example

index.js

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'
import Counter from './components/Counter'
import counter from './reducers'

const store = createStore(counter)

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

Counter.js

import React, { Component } from 'react'

// 把 Redux 中的 value 拿过来用,渲染的时候就可以直接使用 this.props.value
function mapStateToProps(state) {
  return {
    value: state.count
  }
}

// 把 dispatch 也变成了可以直接使用 this.props.onIncreaseClick
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => dispatch({ type: 'increase' })
  }
}

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

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

reducers/index.js

export default = (state = { count: 0 }, action) => {
  const count = state.count
  switch (action.type) {
    case 'increase':
      return { count: count + 1 }
    default:
      return state
  }
}