【问题标题】:React component doesn't rerender with the same props but child state changesReact 组件不会使用相同的道具重新渲染,但子状态会发生变化
【发布时间】:2020-05-28 11:50:50
【问题描述】:

我有以下问题: 我有父组件(按钮在哪里,以及要渲染的子组件数组)。

我向每个孩子传递道具,孩子将其用作状态,然后更改它。 问题是孩子不会重新渲染。

因为这似乎无法理解,这里有一些更清楚的(我希望):

这里是child.js的简化版

export default function ChildComponent(props) {
  const [open, setOpen] = React.useState(props.open);

  const handleClick = () => {
    setOpen(true);
  }; /* i actually never use handleClick */

  const handleClose = (event) => {
    setOpen(open => !open);
  };

  return (
    <div>
        <SomeComponent hideAfterTimeMs={1000} onClose={handleClose}/>
    </div>
  );
}

家长:

import React from "react";
import Child from "./demo";

class MyClass extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      something: false,
    };
  }

  displayKids = () => {
    const a = [];
    for (let i = 0; i < 1; i++) {
      a.push(<Child open={true} key={i} message={"Abcd " + i} />);
    }
    return a; 
  };

  handleChange = e => {
    this.setState(prevState => ({
      something: !prevState.something,
    }));
  };

  render() {
    return (
      <div>
        <button onClick={this.handleChange}>Nacisnij mnie</button>
        {this.displayKids()}
      </div>
    );
  }
}
export default MyClass;

所以基本上子组件渲染, 并将其“打开”设置为假, 当我再次单击按钮时 我希望再次展示孩子, 但什么也没发生。

子渲染几秒钟后消失的东西。

【问题讨论】:

  • 这就是你的代码所做的,所以看起来是意料之中的。你能更具体地说明什么不起作用吗?什么按钮被点击?那么在孩子超时后自动隐藏后,应该重新打开它?
  • 是的,当然。基本上我想多次渲染相同的组件(组件在特定时间后消失,这就是为什么当我单击时我希望它再次渲染)。更具体地说,我单击父组件中的按钮(那里只有一个),然后我想使用 displayKids 方法显示子组件。该按钮改变了一些状态,所以我认为这会导致重新渲染,但它不能那样工作。
  • 子组件的作用是当“open”为“true”时显示某些内容(如某些文本),并在特定时间量(如1000ms)后调用handleClose并更改“open”为“假”。因此,我从父级传递变量 open={true} 并且子级将其用于初始状态(来自道具)
  • 请提供一个有效的sn-p。

标签: javascript reactjs react-native


【解决方案1】:

Keys 帮助 React 识别哪些项目已更改、添加或正在更改 删除。键应该给数组内的元素以给出 元素一个稳定的身份。

您正在使用索引作为键。请尝试使用唯一的密钥。例如。子 ID 或随机哈希码。

如果密钥是唯一且新的,它将重新呈现。现在它没有重新渲染,因为键是相同的。

查看:https://reactjs.org/docs/lists-and-keys.html#keys

【讨论】:

  • 当然,但是......它不会改变任何东西;)
  • 它解决了这个问题。请在您的代码沙箱中尝试。您刚刚将 i 更改为 i.toString(),但“1”仍等于“1”。请更改为独特的东西,例如键={新日期()}。如果您有唯一的密钥,它将重新呈现。如果它具有相同的密钥,则不会重新渲染。见:codesandbox.io/s/material-demo-fxloe
  • 哦,所以每次渲染都必须是新键? :o
  • 如果它有一个新的键,它将被渲染(再次)。否则,它只会在道具更改时重新渲染,但您并不总是有可以或想要更改的道具。
【解决方案2】:

看起来您的组件没有以任何有意义的方式链接。单击My Class 组件上的按钮会更新something 状态,但该状态不会传递给Child 组件。

同样,SomeComponent 组件处理自己的关闭,并告诉 Child 组件它通过 handleClose 关闭 - 但不会与父级通信,父级或 Child 也不会与任何打开通信状态为SomeComponent

更改Child 上的某些状态不会重新呈现它自己的孩子。必须传递一些新的东西作为道具才能发生。

【讨论】:

  • 好吧,也许我再讲一点。我有一个表单,并且 onSubmit 我运行验证功能。在验证函数中,如果某个字段错误,我将此字段名称添加到处于状态的“错误”数组中。例如错误= [“名称”,“地址”]。然后在 displayKids 中迭代错误数组并将错误数组的元素作为子项的道具。因此,当再次单击提交按钮而不更改表单中的任何字段时,错误数组是相同的,孩子们不会呈现。
  • 与此同时,我一直在研究自己的代码和框;)我已经简化了很多事情,因为我仍然不确定您是否了解 prop>state>prop 循环的工作原理做出反应。请看here
  • 好的,我能够更改它以实现我的代码并且它可以工作。您可以将其粘贴(链接到沙箱?)作为您的答案,我会将其标记为正确的答案。非常感谢 ! :)
  • 这是不正确的。如果您将提供一个新的唯一密钥,例如key={new Date()} 它将重新渲染。有关工作示例,请参见 codesandbox.io/s/material-demo-fxloe(唯一更改是关键道具)。
猜你喜欢
  • 2021-06-21
  • 2018-12-31
  • 2021-07-09
  • 2021-09-20
  • 2017-07-22
  • 2020-12-02
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
相关资源
最近更新 更多