繁体   English   中英

子组件不使用更新的道具重新渲染

[英]Child component not re-rendering with updated props

我有一个子组件,它查看并在 DOM 中创建 Canvas 个元素,然后 useEffect() 将内容绘制到这些画布上:

import { useEffect } from "react";

function Table(props) {
  console.log(">> In Table, props is ", props);

  useEffect(() => {
    console.log(">> in useEffect ");

    // prepare the data to render here and render to the multiple HTML Canvases in the DOM
  }, []);

  const options = [
    { value: 0, label: "1" },
    { value: 1, label: "2" }
  ];

  const onChannelXChange = (option) => {
    console.log("1. send the change back to the parent");

    let change = {
      type: "ChannelIndexChange",
      // TODO need to get the plot here
      plotIndex: 0,
      channel: "x",
      value: option.value,
    };
    props.parentCallback(change);
  };

  return (
    <table className="workspace">
      <tbody>
          <tr key={`tr-${fileIndex}`}>
            {props.workspaceState.plots.map((plot, plotIindex) => {
              return (
                <td key={`td-${plotIindex}`}>
                  <div>
                    <canvas
                      className="canvas"
                      id={`canvas-${fileIndex}-${plotIindex}`}
                      width="400"
                      height="400"
                    />
                    <Dropdown
                      options={options}
                      onChange={onChannelXChange}
                      placeholder="Select an option"
                    />
                  </div>
                </td>
              );
            })}
          </tr>
      </tbody>
    </table>
  );
}

export default Table;

它的父组件:

import Table from "./Table";
import React, { useState } from "react";

class Workspace extends React.Component {
  constructor(props) {
    super();

    this.state = {
      workspaceState: {},
    };

    this.state.workspaceState = props.workspaceState;

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

  handleCallback = (option) => {
    this.props.workspaceState.value = option.value;

    // I expect this to re-render the Table Component with the updated props
    console.log("2. updating state");
    this.setState({ workspaceState: this.props.workspaceState });
  };

  render() {
    return (
      <Table
        enrichedEvents={this.props.enrichedEvents}
        workspaceState={this.props.workspaceState}
        className="workspace"
        parentCallback={this.handleCallback}
      ></Table>
    );
  }
}

export default Workspace;

当用户单击下拉菜单时,我将值传回父组件 (Workspace)。 然后这会更新工作区 state,然后我希望重新渲染子组件 - 但事实并非如此。 当我查看日志时,我看到:

Workspace.js:44 1. send the change back to the parent
Workspace.js:44 2. updating parent state component
Table.js:95 >> props is {workspaceState: {...}}

但我没有看到:

 >> in useEffect

我只在应用程序第一次运行时看到此日志。 Table 组件确实获得了新的更新道具,但它不会使用这些新数据重新渲染。 我究竟做错了什么?

该组件绝对重新渲染的(因为这就是 React 的工作方式),但是useEffect挂钩的执行不会耦合到关联组件的每个渲染(事实上,这就是它的目的)。

你提供了useEffect(() => {}, [])

第二个参数是“依赖”数组。 当它为空时, useEffect回调只会在组件第一次挂载后立即执行一次 如果您希望它在某些内容发生变化时再次执行,您需要将更改后的值包含在依赖项数组中。

但是,如果您要使用更改后的值触发某种异步行为,通常只需要这样做。 如果“准备要呈现的数据”只是将其转换为有用的格式,则根本不需要useEffect挂钩; 该逻辑应在 function 正文中为 go。

useEffect(() => {}, []) 替换旧 React 版本中的 componentDidMount,这意味着它只在 DOM 中安装组件后执行一次。 我想知道在你的情况下你是否真的需要一个 useEffect,如果是这种情况你需要使用一个没有依赖关系数组的 useEffect。 像那样:

 import { useEffect } from "react"; function Table(props) { console.log(">> In Table, props is ", props); useEffect(() => { console.log(">> in useEffect "); // prepare the data to render here }); const options = [ { value: 0, label: "1" }, { value: 1, label: "2" } ]; const onChannelXChange = (option) => { console.log("1. send the change back to the parent"); props.parentCallback(option); }; return ( <Dropdown options={options} onChange={onChannelXChange} placeholder="Select an option" /> ); } export default Table;

解决方案 2:正如我所说,我想知道你是否真的需要一个 useEffect 你可以直接这样做

 import { useEffect } from "react"; function Table(props) { console.log(">> In Table, props is ", props); // put you logic directly here // prepare the data to render here const options = [ { value: 0, label: "1" }, { value: 1, label: "2" } ]; const onChannelXChange = (option) => { console.log("1. send the change back to the parent"); props.parentCallback(option); }; return ( <Dropdown options={options} onChange={onChannelXChange} placeholder="Select an option" /> ); } export default Table;

您的效果没有依赖性,因此它将运行一次,类似于 class 组件的生命周期方法 componentDidMount。 如果您希望它在道具的一部分发生变化时运行,例如您需要它作为依赖项。

  useEffect(() => {
    console.log(">> in useEffect ");

    // prepare the data to render here and render to the multiple HTML Canvases in the DOM
  }, [props.workspaceState]);

您应该将父组件的 state 中的 workspaceState 提供给您的子组件。

  <Table
    enrichedEvents={this.props.enrichedEvents}
    workspaceState={this.state.workspaceState}
    className="workspace"
    parentCallback={this.handleCallback}
  ></Table>

您以某种方式试图直接改变父组件的 props,我认为从来没有人建议这样做。 React 不会识别这一点并重新渲染。

  handleCallback = (option) => {
    this.props.workspaceState.value = option.value;

    // I expect this to re-render the Table Component with the updated props
    console.log("2. updating state");
    this.setState({ workspaceState: this.props.workspaceState });
  };

暂无
暂无

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

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