繁体   English   中英

当我更改父组件 state 时,为什么我的 React 子组件没有获取值(重新渲染)?

[英]Why doesn't my React child component get value (re-render) when I change the parent state?

背景

我写了一个带有嵌套子组件的父组件的精确、简短但完整的示例,它只是尝试:

  1. 更改父级 state 中的字符串
  2. 当 Parent 的 state 值更改时,请查看 Child 组件更新 ( this.state.name )

这是应用程序加载时的样子default value从 Parent state 传递给 child 道具。

父/子组件

更改名称

我想要做的就是在用户在父级的<input>中添加新名称并单击父级的<button>后允许更改名称

但是,如您所见,当用户单击按钮时,只会再次呈现 Parent。

问题

  1. 是否有可能让 Child 呈现新值?
  2. 在这个例子中我做错了什么——为什么它不更新或呈现新值?

呈现父更改

所有源代码

这是所有源代码,您可以在我的 StackBlitz 项目中查看和试用

我尽量保持简单。

父组件( DataLoader )

import * as React from 'react';
import { useState } from 'react';
import { Grid } from './Grid.tsx';

interface LoaderProps {
  name: string;
}

export class DataLoader extends React.Component<LoaderProps, {}> {
  state: any = {};
  constructor(props: LoaderProps) {
    super(props);

    this.state.name = this.props.name;

    this.changeName = this.changeName.bind(this);
  }

  render() {
    const { name } = this.state;
    let parentOutput = <span>{name}</span>;
    return (
      <div>
        <button onClick={this.changeName}>Change Name</button>
        <input id="mapvalue" type="text" placeholder="name" />
        <hr id="parent" />
        <div>### Parent ###</div>
        <strong>Name</strong>: {parentOutput}
        <hr id="child" />
        <Grid childName={name} />
      </div>
    );
  }

  changeName() {
    let newValue = document.querySelector('#mapvalue').value.toString();
    console.log(newValue);
    this.setState({
      name: newValue,
    });
  }
}

子组件( Grid

import * as React from 'react';

interface PropsParams {
  childName: string;
}

export class Grid extends React.Component<PropsParams, {}> {
  state: any = {};

  constructor(props: PropsParams) {
    super(props);
    let counter = 0;

    this.state = { childName: this.props.childName };
    console.log(`CHILD -> this.state.name : ${this.state.childName}`);
  }

  render() {
    const { childName } = this.state;
    let mainChildOutput = <span>{childName}</span>;
    return (
      <div>
        <div>### Child ####</div>
        <strong>Name</strong>: {mainChildOutput}
      </div>
    );
  }
}

App.tsx的设置如下——这是 props 的默认值

import * as React from 'react';
import { DataLoader } from './DataLoader.tsx';
import './style.css';

export default function App() {
  return (
    <div>
      <DataLoader name={'default value'} />
    </div>
  );
}

您会看到两个不同的值,因为您正在跟踪两个不同的状态。 一个在父组件中,一个在子组件中。

不要重复数据。

如果子组件应该始终显示传递给它的道具,那么不要在子组件中跟踪 state,只显示传递给它的道具。 例如:

export class Grid extends React.Component<PropsParams, {}> {
  render() {
    const { childName } = this.props; // <--- read the value from props, not local state
    let mainChildOutput = <span>{childName}</span>;
    return (
      <div>
        <div>### Child ####</div>
        <strong>Name</strong>: {mainChildOutput}
      </div>
    );
  }
}

在 Child 组件中,您仅在构造函数中将 prop childName值设置为 state。 构造函数仅在安装组件时执行。 因此,它不知道childName prop 是否稍后更改。

有 2 个解决方案。

(1) 直接使用this.props.childName ,不设置为state。

(2) 添加一个useEffect ,在 prop 更改时更新 state 值。

React.useEffect(() => {
  this.state = {
    childName: this.props.childName;
  };
}, [this.props.childName]);

但是,我推荐第一种解决方案,因为复制数据不是一个好习惯。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM