定制app开发React - Redux Hooks的使用细节详解

文章目录

Hooks

Redux中Hooks介绍

在之前的redux开发中,定制app开发为了让组件和redux结合起来,定制app开发我们使用了react-redux库中的connect:

定制app开发但是这种方式必须使用定制app开发结合返回的高阶组件;

定制app开发并且必须编写:mapStateToProps和 mapDispatchToProps定制app开发映射的函数, 具体使用方式在前面文章有讲解;

在Redux7.1开始,提供了Hook的方式,在函数组件中再也不需要编写connect以及对应的映射函数了

useSelector的作用是将state映射到组件中:

参数一: 要求传入一个回调函数, 会将state传递到该回调函数中; 回调函数的返回值要求是一个对象, 在对象编写要使用的数据, 我们可以直接对这个返回的对象进行解构, 拿到我们要使用state中的数据

const { counter } = useSelector((state) => {  return {    counter: state.counter.counter  }})
  • 1
  • 2
  • 3
  • 4
  • 5

参数二: 可以进行比较来决定是否组件重新渲染;

useSelector默认会比较我们返回的两个对象是否相等;

如何可以比较呢?

  • 在useSelector的第二个参数中, 传入react-redux库中的shallowEqual函数就可以进行比较
import { shallowEqual } from 'react-redux'const { counter } = useSelector((state) => ({  counter: state.counter.counter}), shallowEqual)
  • 1
  • 2
  • 3
  • 4
  • 5

也就是我们必须返回两个完全相等的对象才可以不引起重新渲染;

useDispatch非常简单,就是调用useDispatch这个Hook, 就可以直接获取到dispatch函数,之后在组件中直接使用即可;

const dispatch = useDispatch()
  • 1

我们还可以通过useStore来获取当前的store对象(了解即可, 不建议直接操作store对象);


Redux中Hooks使用

我们来使用Redux的Hooks在App组件实现一个计数器, 在App的子组件中实现一个修改message的案例:

首先我们先创建一个简单的store

// store/modules/counter.jsimport { createSlice } from "@reduxjs/toolkit";const counterSlice = createSlice({  name: "counter",  initialState: {    counter: 10,    message: "Hello World"  },  reducers: {    changeNumberAction(state, { payload }) {      state.counter = state.counter + payload    },    changeMessageAction(state,  {payload }) {      state.message = payload    }  }})export const { changeNumberAction, changeMessageAction } = counterSlice.actionsexport default counterSlice.reducer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
// store/index.jsimport { configureStore } from "@reduxjs/toolkit";import counterSlice from "./modules/counter"const store = configureStore({  reducer: {    counter: counterSlice  }})export default store
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

要使用库需要导入Provider对App组件进行包裹

import React from "react"import ReactDOM from "react-dom/client"import { Provider } from "react-redux"import App from "./12_Redux中的Hooks/App"import store from "./12_Redux中的Hooks/store"const root = ReactDOM.createRoot(document.querySelector("#root"))root.render(  <Provider store={store}>    <App/>  </Provider>)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在组件时使用useSelector和useDispatch实现获取store中的数据和修改store中数据的操作

import React, { memo } from 'react'import { useDispatch, useSelector } from 'react-redux'import { changeMessageAction, changeNumberAction } from './store/modules/counter'// 子组件Homeconst Home = memo(() => {  console.log("Home组件重新渲染")    // 通过useSelector获取到store中的数据  const { message } = useSelector((state) => ({    message: state.counter.message  }))  // useDispatch获取到dispatch函数  const dispatch = useDispatch()  function changeMessage() {    dispatch(changeMessageAction("Hello ChenYq"))  }  return (    <div>      <h2>{message}</h2>      <button onClick={changeMessage}>修改message</button>    </div>  )})// 根组件Appconst App = memo(() => {  console.log("App组件重新渲染")    // 通过useSelector获取到store中的数据  const { counter } = useSelector((state) => ({    counter: state.counter.counter  }))  // useDispatch获取到dispatch函数  const dispatch = useDispatch()  function changeNumber(num) {    dispatch(changeNumberAction(num))  }    return (    <div>      <h2>当前计数: {counter}</h2>      <button onClick={() => changeNumber(1)}>+1</button>      <button onClick={() => changeNumber(-1)}>-1</button>      <Home/>    </div>  )})export default App
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

现在我们已经在组件中使用并且修改了了store中的数据, 但是现在还有一个小问题(性能优化)

当App组件中修改了counter时, App组件会重新渲染这个是没问题的; 但是Home组件中使用的是message, 并没有使用counter, 却也会重新渲染; 同样的在Home子组件中修改了message, 根组件App也会重新渲染; 这是因为在默认情况下useSelector是监听的整个state, 当state发生改变就会导致组件重新渲染

要解决这个问题就需要使用useSelector的第二个参数来控制是否需要重新渲染, 我们只需要在useSelector函数中传入react-redux库中的shallowEqual函数即可, 它内部会自动进行一个浅层比较, 当使用的state中的数据确实发生变化的时候才会重新渲染

import React, { memo } from 'react'import { useDispatch, useSelector, shallowEqual } from 'react-redux'import { changeMessageAction, changeNumberAction } from './store/modules/counter'// 子组件Homeconst Home = memo(() => {  console.log("Home组件重新渲染")  const { message } = useSelector((state) => ({    message: state.counter.message  }), shallowEqual)  const dispatch = useDispatch()  function changeMessage() {    dispatch(changeMessageAction("Hello ChenYq"))  }  return (    <div>      <h2>{message}</h2>      <button onClick={changeMessage}>修改message</button>    </div>  )})// 根组件Appconst App = memo(() => {  console.log("App组件重新渲染")  // 通过useSelector获取到store中的数据  const { counter } = useSelector((state) => ({    counter: state.counter.counter  }), shallowEqual)  // useDispatch获取到dispatch函数  const dispatch = useDispatch()  function changeNumber(num) {    dispatch(changeNumberAction(num))  }    return (    <div>      <h2>当前计数: {counter}</h2>      <button onClick={() => changeNumber(1)}>+1</button>      <button onClick={() => changeNumber(-1)}>-1</button>      <Home/>    </div>  )})export default App
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发