lhk*_*lhk 5 javascript reactive-programming reactjs react-hooks
我的代码有一个组件,它接受两个 props 并拥有自己的内部状态。
仅当组件的 props 更改时,组件才应重新渲染。状态更改不应触发重新渲染。
此行为可以使用基于类的组件和自定义shouldComponentUpdate函数来实现。
然而,这将是代码库中第一个基于类的组件。一切都是通过功能组件和钩子完成的。因此我想知道是否可以使用功能组件来编写所需的功能。
在一些没有解决实际问题的答案之后,我想我必须重新表述我的问题。这是一个包含两个组件的最小示例:
为了演示所需的功能,我使用基于类的组件实现了 Inner。该代码的实时版本可以在codesandbox 上找到。如何将其迁移到功能组件:
Inner.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>
)
}
}
Run Code Online (Sandbox Code Playgroud)
外部.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>
</>
);
}
Run Code Online (Sandbox Code Playgroud)
官方文档说将组件包装在React.memo. 但这似乎并不能阻止状态更改时的重新渲染。它仅适用于道具更改。
我已经尝试过React.memo工作了。您可以在此处查看外部和内部都是功能组件的代码版本。
相关问题:
如何将 shouldComponentUpdate 与 React Hooks 一起使用?:这个问题只涉及道具的变化。接受的答案建议使用React.memo
函数组件中的 shouldComponentUpdate:这个问题早于有状态函数组件。接受的答案解释了功能组件如何不需要,shouldComponentUpdate因为它们是无状态的。
React 的设计是由 setState -> 重新渲染循环驱动的。Props 更改实际上是父组件中某处的 setState。如果您不希望 setState 触发重新渲染,那么为什么首先要使用它呢?
您可以拉入 aconst state = useRef({}).current来存储您的内部状态。
function InnerFunc(props) {
const state = useRef({ innerNum: 0 }).current;
return (
<button
onClick={() => {
state.innerNum = Math.floor(Math.random() * 10);
}}
>
{`${props.outerNum}, ${state.innerNum}`}
</button>
);
}
Run Code Online (Sandbox Code Playgroud)
也就是说,这仍然是一个值得问的问题:“如何以 React hook 方式实现 shouldComponentUpdate?” 这是解决方案:
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])
}
Run Code Online (Sandbox Code Playgroud)
请注意,调用时不可能阻止重新渲染周期setState,上面的钩子仅确保重新渲染的结果与先前渲染的结果保持相同。
| 归档时间: |
|
| 查看次数: |
7649 次 |
| 最近记录: |