gpt4 book ai didi

javascript - React.PureComponent 和子组件

转载 作者:行者123 更新时间:2023-12-05 00:29:43 32 4
gpt4 key购买 nike

有人请用一个简单的例子向我解释 React 文档的最后一段,它是关于 React.PureComponent 的,我见过的所有例子都是高级的,我刚刚开始了解这个概念,我看不出它到底是什么指。 正是 child 也应该“纯洁”的一点 .
据我所知,我认为这种说法言过其实,因为如果父亲不重新渲染自己,那么 children 也不会 ,或者,有什么东西让我无法想象,我无法想象它吗?这就是我需要一个简单示例的原因,我已经在这里查看了所有类似的问题,但它们是高级示例,并未涵盖我正在寻找的内容。
“此外,React.PureComponent 的 shouldComponentUpdate() 会跳过整个组件子树的 prop 更新。 确保所有子组件也是“纯”

最佳答案

我做了一些可以玩的东西。
我认为要实现的重要部分是只有一个区别,它是 shouldComponentUpdate PureComponent 上的实现.
我也对 Make sure all the children components are also “pure” 感到困惑.据我了解,这意味着警告,作为指导方针,而不是绝对不要。当您将父级设置为 PureComponent 时,所有子级都会受到影响。但是有人不习惯shouldComponentUpdate (PureComponent)在树中混合两者时可能会对 child 的行为(不更新)感到惊讶。
以第二个片段 this.state.quotes[0].text = "StackOverflow save the day"; 为例.使用 Component 时两个<List/><ListElement/> , 任意 setState会更新 View 。但是当使用 PureComponent仅在 <List/> , 有人可能会期待 <ListElement/>更新,但不会。
想象一下,而不是写 <List/>作为纯,和<ListElement/>作为不纯洁的,他们警告不要做的事情。你会把两者都写成纯的。你会不会考虑做一些类似 this.state.quotes[0].text = "StackOverflow save the day"; 的事情? ?不,你会从 this.state.quotes[0] = {...} 开始.然后你会看看哪个组件处理上面的数据,quotes数组,处理数组的组件,它是纯的吗?是的,然后写this.state = [{...}]反而。您执行此“重新创建引用/深拷贝”,直到找到第一个非纯组件。如果您遵循他们的建议,在第一个非纯组件处,您知道不会有任何其他过时的引用阻止您的渲染。
如果使用深度比较,您将永远不会遇到这个问题。我正在使用钩子(Hook)组件,它们更加友好。我建议你跳过类组件并使用钩子(Hook)。在 Hook 中实现 shouldComponentUpdate您使用 React.memo .自 您决定如何比较 Prop ,很明显,如果您比较 previousList === newList (浅比较),您将错过列表中的任何更新/添加/删除。当然,您会进行深入比较(使用 deep-equal lib 或(避免)JSON.stringify(previousList) === JSON.stringify(newList) 。请注意,React.Memo 更好还有另一个原因,它只处理 Prop 比较,而不是像 PureComponent 一样处理状态和 Prop 比较。
我认为您不需要每个 child 都使用浅比较,如果组件渲染速度足够快,请使用 shouldComponentUpdate (或 React.memo )可能会使情况变得更糟(记住这是一种性能优化)。
下面展示了我们可以通过浅 Prop 比较(第一个片段)和浅层状态比较(第二个片段)得到的问题:

import { Component, PureComponent } from 'react';

interface Quote {
author: string;
text: string;
}

export class Playground extends Component {
state = {
quotes: [
{
author: 'Ambroise',
text: 'I like React.'
}
]
}

onClickOK () {
this.setState({
quotes: [
{
author: 'Ariel',
text: 'Prefer VueJS.'
}
]
});
}

// https://reactjs.org/docs/react-api.html#reactpurecomponent
// React.PureComponent implements it with a shallow prop and state comparison
// "prop comparison"
onClickIssue() {
if (window['dontMix']) {
alert("Please don't mix on click issues. Reload page.")
return;
}
window['dontMix'] = true;

// This won't work if <List/> is a PureComponent
// Note that we ALSO CHANGED the props for <ListElement/> here, different object, differents strings,
// but <ListElement/> will NOT re-render, regardless of <ListElement/> being pure or not.
const quotesUpdated = this.state.quotes;
quotesUpdated.pop();
quotesUpdated.push({
author: 'Thomas',
text: 'Prefer Angular.'
});

// Shallow props comparison, <List/> will compare array references
// `quotesUpdated === this.state.quotes` and because it is true,
// it will not re-render, or any of the childrens.
//
// The quote object is different, so <ListElement/>
// would be expected to re-render.
this.setState({
quotes: quotesUpdated
});
}

onClickIssue2() {
if (window['dontMix']) {
alert("Please don't mix on click issues. Reload page.")
return;
}
window['dontMix'] = true;

// This won't work if <ListElement/> is a PureComponent since the object in first index stay the same.
// Since we recreate the array, <List/> will always re-render regardless of <List/> being pure.
this.state.quotes[0].author = "Thomas";
this.state.quotes[0].text = "Prefer Angular.";
this.setState({
quotes: [
this.state.quotes[0],
]
});
}

render() {
return (
<section>
<button onClick={this.onClickOK.bind(this)}>Get updated</button>
<button onClick={this.onClickIssue.bind(this)}>Problem</button>
<button onClick={this.onClickIssue2.bind(this)}>Problem2</button>
<List quotes={this.state.quotes}/>
</section>
);
}
}

// Change PureComponent to Component, no problem with shallow comparison anymore.
class List extends PureComponent<{ quotes: Quote[]; }>{
render() {
return (
<ul>
{
this.props.quotes.map(
(e, i) => <ListElement key={i} quote={e}/>
)
}
</ul>
);
}
}

class ListElement extends PureComponent<{quote: Quote}> {
render() {
return (
<li>
<h3>{this.props.quote.author}</h3>
<p>{this.props.quote.text}</p>
</li>
);
}
}
第二个片段,侧重于状态浅比较,以及 <ListElement/>Component 开头这次不是 PureComponent .
import { Component, PureComponent } from 'react';

interface Quote {
author: string;
text: string;
}

export class Playground2 extends Component {
state = {
quotes: [
{
author: 'Ambroise',
text: 'I like React.'
}
]
};

render() {
return (
<section>
<List quotes={this.state.quotes}/>
</section>
);
}
}

// Note: Careful not to confuse state.quotes and props.quote
class List extends PureComponent<{ quotes: Quote[]; }> {
state = {
quotes: this.props.quotes
};

// https://reactjs.org/docs/react-api.html#reactpurecomponent
// React.PureComponent implements it with a shallow prop and state comparison
// "state comparison"
fail() {
for (let i = 0; i < this.state.quotes.length; i++) {
this.state.quotes.pop();
}

this.setState({
quotes: this.state.quotes
});
}

success() {
// This will never work, because `previousState === newState` (both are this.state)
// this.state.quotes = [];
// this.setState(this.state);

this.setState({
quotes: []
});
}

// It work if you change this class to Component
changeChild() {
// if you clicked another button reload the page to get initial state.
if (this.state.quotes.length === 0) {
alert("You clicked another button. Please reload page to test this one.");
}

// previously "I like React."
this.state.quotes[0].text = "StackOverflow save the day";

// NOTICE: Choose only one setState bellow, comment the others.

// Won't work
// this.setState({
// quotes: this.state.quotes
// });

// This will never work, because `previousState === newState` (both are this.state)
// this.state.quotes = [this.state.quotes[0]];
// this.setState(this.state);

// Won't work
this.setState(this.state);

// This will work when <List/> is a PureComponent and <ListElement/> a Component,
// both this.state and this.state.quotes are different
// this.setState({
// quotes: [this.state.quotes[0]]
// });
}

render() {
return (
<div>
<button onClick={this.fail.bind(this)}>Empty the list (FAIL if PureComponent)</button>
<button onClick={this.success.bind(this)}>Empty the list (SUCCESS)</button>
<button onClick={this.changeChild.bind(this)}>Change child (FAIL if PureComponent)</button>
<ul>
{
this.state.quotes.map(
(e, i) => <ListElement key={i} quote={e}/>
)
}
</ul>
</div>
);
}
}

// ATTENTION: This one start as a Component this time, instead of a PureComponent
class ListElement extends Component<{quote: Quote}, {author: string}> {
state = {
author: this.props.quote.author,
};

// Yep this work.
takeOwnership() {
this.setState({
author: "Constantin"
})
}

render() {
return (
<li>
<button onClick={this.takeOwnership.bind(this)}>Take ownership !</button>
<h3>{this.state.author}</h3>
<p>{this.props.quote.text}</p>
</li>
);
}
}
TLDR;我也觉得它令人困惑,它看起来更像是和建议,我建议不要过多关注它,并使用钩子(Hook)组件,您可以在其中进行更细粒度的控制,通过 Prop /状态比较和浅/深比较。

关于javascript - React.PureComponent 和子组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72409607/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com