Skip to content

redux

Redux 是 React 最常用的集中状态管理工具,类似于 Vue 中的 Pina/Vuex, 可以独立于框架运行。

作用:通过集中管理的方式管理应用的状态。

Redux数据流

使用步骤:

  1. 定义一个 reducer函数(根据当前想要做的修改返回一个新的状态)
  2. 使用 createStore方法 传入 reducer 函数, 生成一个 store 实例对象
  3. 使用 store 实例subscribe 方法 订阅数据的变化(数据一旦变化,可以得到通知)
  4. 使用 store 实例的 dispatch 方法提交 action 对象 触发数据变化(告诉 reducer 怎么改数据)
  5. 使用 store 实例的 getState 方法 获取最新的状态数据更新到视图中
HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/redux/4.0.0/redux.js"></script>
  </head>
  <body>
    <button id="decrement">-</button>
    <span id="count">0</span>
    <button id="increment">+</button>
    <script>
      // 1. 定义reducer函数
      // 作用:根据不同的action对象,返回不同的新的state
      // state: 管理的数据初始状态
      // action: 对象type标记当前想要做什么样的修改
      function reducer(state = { count: 0 }, action) {
        // 数据不可变:基于原生状态生成一个新的状态
        if (action.type === 'INCREMENT') {
          return { count: state.count + 1 }
        }
        if (action.type === 'DECREMENT') {
          return { count: state.count - 1 }
        }
        return state
      }

      // 2. 使用reducer函数生成store实例
      const store = Redux.createStore(reducer)

      // 3. 通过store实例的subscribe订阅数据变化
      // 回调函数可以在每次state发生变化的时候自动执行
      store.subscribe(() => {
        console.log('state变化了...', store.getState())
        document.getElementById('count').innerHTML = store.getState().count
      })

      // 4. 通过store实例的dispatch函数提交action更改状态
      const inBtn = document.getElementById('increment')
      inBtn.addEventListener('click', () => {
        store.dispatch({ type: 'INCREMENT' })
      })

      const dBtn = document.getElementById('decrement')
      dBtn.addEventListener('click', () => {
        store.dispatch({ type: 'DECREMENT' })
      })
    </script>
  </body>
</html>

Redux 在 react 项目中的环境准备

在 React 中使用 redux,官方要求安装两个其他的插件 Redux Toolkitreact-redux

bash
npm i @reduxjs/toolkit react-redux
  • Redux Toolkit: 是官方推荐编写 Redux 逻辑的方式,是一套工具的集合,简化书写方法

    1. 简化 Store 的配置方式
    2. 内置 immer 支持可变式状态修改
    3. 内置 thunk 更好的异步创建
  • react-redux:用来 链接 Redux 和 React 组件的中间件

Redux和React的关系

在 React 中使用 redux

Redux和React的关系

1.使用 React Toolkit 创建 counterStore

jsx
import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({
  name: 'counterStore'
  initialState: {
    count: 0
  },
  reducers: {
    increment: state => {
      state.count++
    },
    decrement: state => {
      state.count--
    }
  }
})

const { increment, decrement } = counterStore.actions;

const counterReducer = counterStore.reducer;

export { increment, decrement };
export default counterReducer;
jsx
import { configureStore } from '@reduxjs/toolkit'

import counterStore from './modules/counterStore'

const store = configureStore({
  reducer: {
    counterStore: counterStore.reducer
  }
})

export default store

2. 为 react 注入 store

react-redux 负责把 Redux 和 React 链接起来,内置 Provider 组件,通过 store 参数把创建好的 store 实例注入到应用中,链接正式建立

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

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
)

3.React 组件中使用 store 中的数据

在 React 组件中使用 store 中的数据,需要用到一个钩子函数 useSelector, 它的作用是把 store 中的数据映射到组件中

jsx
import { useSelector } from 'react-redux'

function ReduxExample() {
  const { count } = useSelector((state) => state.counter)
  return <div>{count}</div>
}

4.修改 store 中的数据

在 React 组件中修改 store 中的数据,需要用到一个 useDispatch 钩子函数,它的作用是返回一个函数,可以用来触发 store 中的 reducer 函数,修改数据

jsx
import { useSelector, useDispatch } from 'react-redux'

import { increment, decrement } from './store/modules/counterStore'

function ReduxExample() {
  const { count } = useSelector((state) => state.counter)
  const dispatch = useDispatch()
  return (
    <div>
      <button onClick={() => dispatch(increment())}>-</button>
      <span>{count}</span>
      <button onClick={() => dispatch(decrement())}>+</button>
    </div>
  )
}