redux最佳实践

2,326 阅读2分钟

redux 核心概念 action(type数据操作方式,payload参数)、reducer(初始化数据,根据action.type去执行不同操作。)、store(核心仓库数据,初始化传入reducer)

reducer 理解为催化剂,把action和store反应生成新store


redux最重要的就是从业务组建中脱离出来,作为一个数据库,对修改以及取都能做到收口的奇效

项目实践

npm i @reduxjs/toolkit react-redux

@reduxjs/toolkit

简化redux使用流程,以前需要创建actions reducers等文件夹,现在提出slice(片)概念,整合了action 和 reduce。

原来在reducer函数里判断action type

现在将reducers配置拆分成多个action操作函数

默认将action.type === slice注册名/action操作函数名

react-redux

提供 provider 组件,负责触发页面更新。

新版使用 hooks useSelector取值, useDispatch 更新

旧版 connect 函数在ui组件包一层数据逻辑层,通过prop传入redux state 和 修改方法,左手ui右手store

splice

import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      // store不可直接修改,这里提供数据变异方法,是草稿副本更新完覆盖state操作。
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    },
  },
})
// 同步修改
export const { increment, decrement, incrementByAmount } = counterSlice.actions

// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched
// 异步更新
export const incrementAsync = (amount) => (dispatch) => {
  setTimeout(() => {
    dispatch(incrementByAmount(amount))
  }, 1000)
}

// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state) => state.counter.value)`
// selector 取值操作~ 组件页面行内直接取也行
export const selectCount = (state) => state.counter.value

export default counterSlice.reducer

store.js

import { configureStore } from "@reduxjs/toolkit"
import counterReducer from './userSlice.js'

const store = configureStore({
    reducer: {
        counter: counterReducer  // slice注册名
    }
})

export default store

index.js

增加Provider组件

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

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

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

jsx

hooks api

import {useSelector,useDispatch } from 'react-redux'
import {selectCount,increment, decrement, incrementByAmount, incrementAsync} from '../store/splice/count'

export default function StorePage() {
  // 取值
  const count = useSelector((state) => state.counter.value)
  const count2 = useSelector(selectCount)
  const dispatch = useDispatch()
  return (
    <div>
      {count}
      {count2}
      // 修改值
      <button onClick={()=>dispatch(increment())}>+</button>  
      <button onClick={()=>dispatch(decrement())}>-</button>  
      <button onClick={()=>dispatch(incrementByAmount(100))}>aaa</button>  
      <button onClick={()=>dispatch(incrementAsync(1000))}>bbb</button>  
    </div>
  )
}

connect api

import {connect} from 'react-redux'
import {selectCount,increment} from '../store/splice/count'

function UIcomponent(props){
    props.count
    props.increment()
}

export default connect(
  state => ({
      count: state.count
  }),
  {
    increment,selectCount
  }
)(UIcomponent)