我的代码有一个组件,它既有道具,又有自己的内部状态
组件只有在其道具发生变化时才应重新加载。状态更改不应触发重新加载
此行为可以通过基于类的组件和自定义的shouldComponentUpdate
函数实现
然而,这将是代码库中第一个基于类的组件。一切都是通过功能组件和挂钩完成的。因此,我想知道是否可以使用功能组件对所需的功能进行编码。
在回答了一些与实际问题不符的问题后,我想我必须重新表述我的问题。以下是一个包含两个组件的最小示例:
为了演示所需的功能,我使用基于类的组件实现了内部功能。此代码的实时版本可以在codesandbox上找到。如何将其迁移到功能组件:
我nner.tsx:
import React, { Component } from 'react'
interface InnerProps{outerNum:number}
interface InnerState{innerNum:number}
export default class Inner extends Component<InnerProps, InnerState> {
state = {innerNum:0};
shouldComponentUpdate(nextProps:InnerProps, nextState:InnerState){
return this.props != nextProps;
}
render() {
return (
<button onClick={()=>{
this.setState({innerNum: Math.floor(Math.random()*10)})
}}>
{`${this.props.outerNum}, ${this.state.innerNum}`}
</button>
)
}
}
outer.tsx:
import React, { useState } from "react";
import Inner from "./Inner";
export default function Outer() {
const [outerState, setOuterState] = useState(1);
return (
<>
<button
onClick={() => {
setOuterState(Math.floor(Math.random() * 10));
}}
>
change outer state
</button>
<Inner outerNum={outerState}></Inner>
</>
);
}
官方文档说用React.memo
包装组件。但这似乎不适用于防止状态变化的重新呈现。它只适用于道具更改。
我试着让做出反应。备忘录
工作。您可以在这里看到代码的一个版本,其中外部和内部都是功能组件。
相关问题:
如何在React Hooks中使用应该组件更新?:这个问题只涉及道具更改。接受的答案建议使用React.memo
应该在功能组件中更新组件:这个问题早于有状态的功能组件。公认的答案解释了为什么功能组件不需要shouldComponentUpdate
,因为它们是无状态的。
不停止状态更改
反应备忘录只检查道具的变化。如果您的功能组件包装在React中。memo的实现中有一个useState或useContext钩子,当状态或上下文发生变化时,它仍然会重新启动。
参考:-https://reactjs.org/docs/react-api.html#reactmemo
您的内部
组件取决于外部
组件的属性num
,您不能阻止它呈现属性更改,因为React.memo
进行属性比较:
// The default behaviour is shallow comparison between previous and current render properties.
const areEqual = (a, b) => a.num === b.num;
export default React.memo(Inner, areEqual);
通过记忆内部
组件并删除num
依赖项,它将不会在外部
渲染时渲染,请参见附带的沙盒。
export default function Outer() {
const [outerState, setOuterState] = useState(1);
return (
<>
...
// v Inner is memoized and won't render on `outerState` change.
<Inner />
</>
);
}
如果你想用钩子实现\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
const [currState] = useState();
// shouldUpdateState your's custom function to compare and decide if update state needed
setState(prevState => {
if(shouldUpdateState(prevState,currState)) {
return currState;
}
return prevState;
});
React是由setState驱动的设计-
您可以拉入一个const state=useRef({})。当前
以存储内部状态。
function InnerFunc(props) {
const state = useRef({ innerNum: 0 }).current;
return (
<button
onClick={() => {
state.innerNum = Math.floor(Math.random() * 10);
}}
>
{`${props.outerNum}, ${state.innerNum}`}
</button>
);
}
尽管如此,仍然有一个合理的问题要问:“如何以反应挂钩的方式实现应该组件更新?”解决办法是:
function shouldComponentUpdate(elements, predicate, deps) {
const store = useRef({ deps: [], elements }).current
const shouldUpdate = predicate(store.deps)
if (shouldUpdate) {
store.elements = elements
}
store.deps = deps
return store.elements
}
// Usage:
function InnerFunc(props) {
const [state, setState] = useState({ innerNum: 0 })
const elements = (
<button
onClick={() => {
setState({ innerNum: Math.floor(Math.random() * 10) });
}}
>
{`${props.outerNum}, ${state.innerNum}`}
</button>
);
return shouldComponentUpdate(elements, (prevDeps) => {
return prevDeps[0] !== props
}, [props, state])
}
注意,当调用setState
时,不可能阻止重新渲染循环,上面的钩子仅确保重新渲染的结果与先前渲染的结果保持相同。