react,redux store更新与memo、Pure组件、shouldUpdate
发布于 作者:苏南大叔 来源:程序如此灵动~
大家都知道react里面的context功能和redux是非常类似的,当redux的store里面的数据更新的时候,组件也会跟着更新。那么,这里有个疑问,如果碰到了使用memo的组件,或者是PureComponent,或者是shouldComponentUpdate为false的组件,或者是根本就没有使用到redux但是被包裹在Prodiver内部的组件。子组件会跟着redux的store数据更新而更新么?这就是本文要探讨的问题。

大家好,这里是苏南大叔的程序如此灵动博客,这里记录苏南大叔和计算机代码的故事。本文描述redux的store数据更新是否会引起子组件更新的问题。测试环境:create-react-app@5.0.1,node@16.14.2,react@18.2.0,react-dom@18.2.0,react-redux@8.0.5,@reduxjs/toolkit@1.9.0。本文一句话总结就是:被redux的Prodiver包裹的子组件里面,数据变子组件就会被更新。但是目前有一个特例,就是:“shouldComponentUpdate:false”的组件。
本文对标文章:
https://newsn.net/say/react-context-update.html
前置内容
本文的正确理解,您可能需要下面的文章:
- https://newsn.net/say/react-memo.html
- https://newsn.net/say/react-context.html
- https://newsn.net/say/react-pure-component.html
- https://newsn.net/say/redux.html
- https://newsn.net/say/redux-2.html
测试代码之基本部分
import React, { useState, useRef, memo, PureComponent, useEffect } from "react";
import { createStore } from 'redux';
import { Provider, useSelector } from 'react-redux';
import { connect } from 'react-redux';
const sunanStore = createStore((state = { sunan: { value: "未更新" } }, action) => {
switch (action.type) {
case 'sunan/setReduxValue':
return { sunan: { value: action.value } }
default:
return state
}
})
const Sunan = () => {
const [status, setStatus] = useState("未更新");
useEffect(() => {
let status = sunanStore.getState().sunan.value;
setStatus(status);
sunanStore.subscribe(() => {
let status = sunanStore.getState().sunan.value;
setStatus(status);
})
}, []);
const change = () => {
sunanStore.dispatch({ type: 'sunan/setReduxValue', value: ("已更新") })
}
return (
<div>
<p>测试Redux是否会引起子组件更新</p>
redux store内的值:{status}
<button onClick={() => change()}>{"点击按钮更新redux数据"}</button><br />
<Provider store={sunanStore}>
<Sunan1 />
<Sunan2 />
<Sunan3 />
<Sunan4 />
<Sunan5 />
<Sunan6 />
<Sunan7 />
</Provider>
</div>
);
};
export default Sunan;
测试代码之组件部分
第一个测试组件:使用memo的函数式组件。
function Sunan1_() {
const isMounted = useRef(null);
if (isMounted.current) {
console.log("sunan1 update")
} else {
isMounted.current = true;
}
const status = useSelector((state) => state.sunan.value);
return (
<>sunan1(memo)_: {status}<br /></>
)
}
const Sunan1 = memo(Sunan1_)第二个测试组件:使用PureComponent的类式组件。
class Sunan2_ extends PureComponent {
constructor(props) {
super(props);
}
componentDidUpdate() {
console.log("Sunan2 update");
}
render() {
const status = this.props.sunan.value;
return (
<>Sunan2(pure)___: {status}<br /></>
)
}
}
const mapStateToProps = state => {
return {
sunan: state.sunan
}
}
const Sunan2 = connect(mapStateToProps)(Sunan2_);第三个测试组件:使用shouldComponentUpdate主动阻止更新的类式组件。【特例】【特例】【特例】
class Sunan3_ extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps, nextState) {
return false;
}
componentDidUpdate() {
console.log("Sunan3 update");
}
render() {
const status = this.props.sunan.value;
return (
<>Sunan3(should:false) : {status}<br /></>
)
}
}
const Sunan3 = connect(mapStateToProps)(Sunan3_);第四个测试组件:使用了useSelector普通函数式组件。
function Sunan4() {
const isMounted = useRef(null);
if (isMounted.current) {
console.log("sunan4 update")
} else {
isMounted.current = true;
}
const status = useSelector((state) => state.sunan.value);
return (
<>sunan4(useContext)<br /></>
)
}第五个测试组件:没使用任何Redux相关的普通函数式组件。
function Sunan5() {
const isMounted = useRef(null);
if (isMounted.current) {
console.log("sunan5 update")
} else {
isMounted.current = true;
}
return (
<>sunan5(---------)<br /></>
)
}第六个测试组件:使用了shouldComponentUpdate:true普通类式组件。
class Sunan6 extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate() {
return true;
}
componentDidUpdate() {
console.log("Sunan6 update");
}
render() {
return (
<>Sunan6(should:True) : <br /></>
)
}
}第七个测试组件:没使用任何redux的普通类式组件(其实和第六个一样)。
class Sunan7 extends React.Component {
constructor(props) {
super(props);
}
componentDidUpdate() {
console.log("Sunan7 update");
}
render() {
return (
<>Sunan7(------) <br /></>
)
}
}测试结果
通过触发父组件里面的按钮,更新store内的数据,结果显示:Prodiver包裹的全部组件都更新了。即使是memo、PureComponent、甚至根本没有用的context任何功能的组件。

【但是】【但是】【但是】【但是】【但是】shoudComponentUpdate为false的组件,可以阻止这个更新。这一点可能就是和context更新引起子组件更新的不同之处。
【但是】【但是】【但是】【但是】【但是】
结束语
所以,本文的结论是:只要redux的store更新,内部包裹的组件除了“shouldComponentUpdate:false”的类式组件不会更新,其它任何组件都会更新。如果您知道如何作用某个组件不更新,可以留言给我。