React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > redux中的hooks使用

redux中的hooks使用详解

作者:改了一个昵称

useSelector从Redux提取状态,配合shallowEqual和memo优化渲染性能;Reselect通过缓存减少重复计算,适用于复杂选择器逻辑,提升效率

useSelector

基础使用

import { useSelector } from 'react-redux'
import { memo } from 'react'

const App = memo(() => {
	` 使用 useSelector 将 Redux Store 中的数据映射到组件内 `
	` state 参数:代表整个 Redux Store 的根状态(root state) `
	const { count } = useSelector((state) => {
		return {
			`假设你的 Redux Store 中有一个名为 counter 的 slice(分片),该 slice 的状态中包含 count 字段`
			count: state.counter.count
		}
	})

	return (
		<div>
			<h2>count: {count}</h2>
		</div>
	)
})

这里memo的作用:

适用场景:

memo 与 useSelector 的关系:

第二个参数 shallowEqual

父组件修改count时,App依赖的count发生改变,所以,父组件App会重新渲染,

但是,此时子组件也重新渲染了,子组件并没有依赖count,而且子组件此时是用memo包裹的,memo包裹的组件只有当其props发生改变时,才会重新渲染。

当子组件修改msg时,App组件也重新渲染了。

这是因为使用了useSelector,useSelector 监听的是 整个state数据,如果state里有任何数据发生变化,当前组件就会重新渲染。

而正常情况下,应该是:

useSelector的第二个参数:用来比较来决定组件是否需要渲染,当state发生改变时,useSelector 将本次映射的值与上次映射的值有没有发生改变,有改变则重新渲染,没有改变则不变。

// state发生变化时,父组件的useSelector判断本次映射的count与上次映射的count是否一致,不一致则重新渲染,否则不重新渲染
const { count } = useSelector((state) => {
	return {
		count: state.counter.count
	}
}, shallowEqual)

// state发生变化时,子组件的useSelector判断本次映射的msg与上次映射的msg是否一致,不一致则重新渲染,否则不重新渲染
const { msg } = useSelector((state) => {
	return {
		msg: state.counter.msg
	}
}, shallowEqual)

Reselect

Reselect 是一个专为 Redux 设计的记忆化选择器库,用于优化从 Redux Store 中提取数据的性能。

它的核心思想是:通过缓存(memoization)避免重复计算,确保只有在相关状态变化时,才重新执行选择器逻辑。

(1) 什么是记忆化(Memoization)?

(2) Reselect 的作用

场景

优势

Reselect 的核心 API:createSelector

用法:

import { createSelector } from 'reselect'

`输入选择器:从状态中提取原始数据`
const selectUser = (state) => state.user       【state.user 是 Redux Store 中的一个 slice】
const selectPosts = (state) => state.posts     【state.posts 是 Redux Store 中的一个 slice】

`Reselect 的 createSelector 会按顺序将 输入选择器的返回值,作为参数传递给转换函数。
 因此,转换函数中的
   user  对应 selectUser的返回值(即state.user)
   posts 对应 selectPosts的返回值(即state.posts)`
const selectUserData = createSelector(
	[selectUser, selectPosts],    `【输入选择器数组】`
	(user, posts) => ({           `【转换函数】`
		username: user.name,
		postCount: posts.length,
	})
)

某组件如下:

import { useSelector } from 'react-redux'
import { selectUserData } from './selectors'

const Component = () => {
	const { username, postCount } = useSelector(selectUserData)
	
	return (
		<div>
			<h3>{username}</h3>
			<p>Posts: {postCount}</p>
		</div>
	)
}

执行流程:

首次调用

后续调用

结合shallowEqual

const { username, postCount } = useSelector(
	selectUserData,
	shallowEqual
)

高级用法:组合选择器

多层选择器

const selectUser = (state) => state.user
const selectPosts = (state) => state.posts

const selectUserData = createSelector(
	[selectUser, selectPosts],
	(user, posts) => ({
		username: user.name,
		postCount: posts.length,
	})
)

const selectUserStats = createSelector(
	[selectUserData],
	(userData) => ({
		avgPostsPerDay: userData.postCount / 30,
	})
)

带参数的选择器

const selectPostById = (postId) => createSelector(
	[(state) => state.posts],
	(posts) => posts.find(post => post.id === postId)
)

// 组件中使用
const Component = ({ postId }) => {
	const post = useSelector(() => selectPostById(postId))
	return <div>{post.title}</div>
}

深入解析:Reselect 的工作原理

(1) 输入选择器的顺序

输入选择器的顺序会影响缓存键的计算。例如:

const selectorA = createSelector(
  [selectX, selectY],
  (x, y) => x + y
);

const selectorB = createSelector(
  [selectY, selectX],
  (y, x) => y + x
);

(2) 缓存的生命周期

(3) 深层嵌套状态的处理

const selectDeepData = createSelector(
  [(state) => state.deep.nested.data],
  (data) => data.value
);

总结:

Reselect 的本质:通过记忆化选择器,避免重复计算,优化性能。

适用场景:当选择器逻辑复杂、依赖多个状态片段或需要组合数据时。

最佳实践

useDispatch获取dispatch函数

` 派发操作 `
const dispatch = useDispatch()

function calNumber (num) {
	dispatch(addNumberAction(num))
}

return (
	<div>
		<h2>count:{count}</h2>
		<button onClick={e => calNumber(1)}> +1 </button>
	</div>
)

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文