寻雾启示

V1

2022/07/31阅读:12主题:全栈蓝

React中使用Redux的不同写法

今天来记录一下,在React中使用Redux的不同写法,从最开始的不依赖react-redux插件,到妥协(bushi),直到现在使用@reduxjs/toolkit插件进行编写,了解插件到底为我们做了什么(他真的,我哭死o(╥﹏╥)o)。

第一种,纯redux

创建store

/**
 * 目前createStore已经弃用,所以我们要引用legacy_createStore 
 * compose:用来合成函数,在同时配置applyMiddleware、devtool时候需要引入
 * applyMiddleware:使用中间件来增强store
 * thunk:创建异步actions
 * devtool:判断浏览器是否有安装调试的插件,有则启用
 */
import { legacy_createStore as createStore, compose, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import count from './features/count'

const devtool = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

export default createStore(
  combineReducers({
    count
  }),
  compose(
    applyMiddleware(thunk),
    devtool
  )
)

创建reducer

/**
 * 以一个简单的累加计数器为例
 * reducer是一个函数,初始化会调用,所以要设置默认值
 * 工作原理:根据传入的actionType,执行对应的逻辑
 */
const initState = 0
const reducer = (preState = initState, action) => {
  const { type, playload } = action
  switch (type) {
    case 'add':
      return preState + playload
    default:
      return preState
  }
}

export default reducer

组件引用store

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import store from './store'

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

// 监听state变化,更新视图
store.subscribe(() => {
  root.render(
    <React.StrictMode>
      <App store={store} />
    </React.StrictMode>
  )
})
// HelloWorld.js
import React from 'react'

const HelloWorld = props => {
  const store = props.store
  return (
    <div>
      {/* 获取state */}
      <div>HelloWorld,{store.getState()}</div>
      {/* 通过dispatch触发调用reducer,传入约定好的action */}
      <button onClick={() => store.dispatch({ type'add', payload: 1 })}>
        点击加1
      </button>
    </div>
  )
}

export default HelloWorld

第二种,使用react-redux

与第一种的区别在于组件引用,不需要再手动监听state变化。同时组件分为UI组件、容器组件。UI组件所需的状态,更新状态的方法均由容器组件提供,通过props的方法传递。

组件引用store

// src/index.js
// 使用Provider组件注入store
import { Provider } from 'react-redux'
import store from './store'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
)
// HelloWorld.js
import React from 'react'
// 引入connect函数创建容器组件,ui组件不直接操作state
import { connect } from 'react-redux'

const HelloWorld = props => {
  return (
    <div>
      <div>HelloWorld,{props.value}</div>
      <button onClick={() => props.add(1)}>按钮</button>
    </div>
  )
}

// 设置给UI组件展示的参数
const mapDispatchToProps = store => {
  return {
    value: store,
  }
}

// 设置给UI组件调用的方法
const MapDispatchToPropsNonObject = {
  add: payload => ({ type'add', payload }),
}

export default connect(
  mapDispatchToProps,
  MapDispatchToPropsNonObject
)(HelloWorld)

第三种,使用@reduxjs/toolkit + react-redux

创建store

// store/index.js
// 使用configureStore方法创建store
import { configureStore } from '@reduxjs/toolkit'
import countReducer from './features/count'

export default configureStore({
  reducer: {
    count: countReducer
  }
})

创建reducer

// 使用createSlice创建reducer,createAsyncThunk创建异步actions
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'

const request = () => {
  return fetch('http://xxx.xxxxxxxxx.xxx').then(res => {
    return res.json()
  })
}

export const asyncReducer = createAsyncThunk('count/asyncAdd', async () => {
  const res = await request()
  return res
})

const slice = createSlice({
  name: 'count',
  initialState: {
    value: 0,
    list: [],
  },
  reducers: {
    add(state) {
      state.value += 1
    },
  },
  // 监听异步action完成
  extraReducers(builder) {
    builder.addCase(asyncReducer.fulfilled, (state, { payload }) => {
      state.list = payload.movieList
    })
  },
})

export const { add } = slice.actions

export default slice.reducer

组件引用

// HelloWorld.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { add, asyncReducer } from '../store/features/count'

const HelloWorld = () => {
  // 从store中获取状态
  const { value, list } = useSelector(store => {
    return store.count
  })
  
  // 从store中对dispatch函数的引用
  const dispatch = useDispatch()
  return (
    <div>
      <div>value:{value}</div>
      <button onClick={() => dispatch(add())}>点击加1</button>
      <button onClick={() => dispatch(asyncReducer())}>异步action</button>
      <div>
        {list.length}
      </div>
    </div>
  )
}

export default HelloWorld

总结

使用了插件之后,我们使用store不再需要手动监听state变化,更新视图;reducer的定义变得更加规范,方便维护;组件引用store也变得更加方便,减少了很多的代码量。提高了开发效率。

分类:

前端

标签:

React.js

作者介绍

寻雾启示
V1