Redux Hooks怎样使用,有哪些要注意的细节呢
Admin 2022-11-12 群英技术资讯 437 次浏览
在之前的redux开发中,为了让组件和redux结合起来,我们使用了react-redux库中的connect:
但是这种方式必须使用高阶函数结合返回的高阶组件;
并且必须编写:mapStateToProps和 mapDispatchToProps映射的函数, 具体使用方式在前面文章有讲解;
在Redux7.1开始,提供了Hook的方式,在函数组件中再也不需要编写connect以及对应的映射函数了
useSelector
的作用是将state映射到组件中:
参数一: 要求传入一个回调函数, 会将state传递到该回调函数中; 回调函数的返回值要求是一个对象, 在对象编写要使用的数据, 我们可以直接对这个返回的对象进行解构, 拿到我们要使用state中的数据
const { counter } = useSelector((state) => { return { counter: state.counter.counter } })登录后复制参数二: 可以进行比较来决定是否组件重新渲染;
useSelector默认会比较我们返回的两个对象是否相等;
如何可以比较呢?
- 在useSelector的第二个参数中, 传入react-redux库中的
shallowEqual
函数就可以进行比较
import { shallowEqual } from 'react-redux' const { counter } = useSelector((state) => ({ counter: state.counter.counter }), shallowEqual)登录后复制也就是我们必须返回两个完全相等的对象才可以不引起重新渲染;
useDispatch
非常简单,就是调用useDispatch这个Hook, 就可以直接获取到dispatch函数,之后在组件中直接使用即可;
const dispatch = useDispatch()
登录后复制
我们还可以通过useStore来获取当前的store对象(了解即可, 不建议直接操作store对象);
我们来使用Redux的Hooks在App组件实现一个计数器, 在App的子组件中实现一个修改message的案例:
首先我们先创建一个简单的store
// store/modules/counter.js
import { 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.actions
export default counterSlice.reducer
登录后复制
// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import counterSlice from "./modules/counter"
const store = configureStore({
reducer: {
counter: counterSlice
}
})
export default store
登录后复制
要使用react-redux库需要导入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>
)
登录后复制
在组件时使用useSelector和useDispatch实现获取store中的数据和修改store中数据的操作
import React, { memo } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { changeMessageAction, changeNumberAction } from './store/modules/counter'
// 子组件Home
const 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>
)
})
// 根组件App
const 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
登录后复制
现在我们已经在组件中使用并且修改了了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'
// 子组件Home
const 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>
)
})
// 根组件App
const 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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
最终效果展示xhr发起请求!DOCTYPE htmlhtml lang=en head meta charset=UTF-8 meta http-equiv=X-UA-Compatible content=IE=edge meta name=viewport content=width=device-
这篇文章主要介绍了vue3自定义dialog、modal组件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
用原生JavaScript如何实现换肤效果?在前端开发中,换肤效果也是比较常遇到需求,例如一些导航网站就有网页换肤功能。而要实现js换肤的原理其实很简答,就是用JS切换到对应的CSS样式表文件就可以实现了。下面是用原生JS现实的简单换肤效果,供大家参考。
这篇文章主要介绍了React中使用window.print()出现页面无响应问题解决记录,首先问题原因可能是操作了document但是并未进行销毁(可能是),具体问题解决思路参考下本文吧
这篇文章主要为大家详细介绍了Vues实现跑马灯效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008