Javascript 为什么';当其道具更改时,此React组件是否重新渲染?

Javascript 为什么';当其道具更改时,此React组件是否重新渲染?,javascript,reactjs,react-native,react-hooks,Javascript,Reactjs,React Native,React Hooks,我已经创建了一个重新渲染问题的简化版本,我正在处理一个应用程序 实际上,displayement1和displayement2是两个复杂的组件 displayement2这里是通过一个简单的数字数组(通过其道具numbers提供)迭代并显示它们 问题:当数字道具后面的数组在主组件应用程序中更新时(在这种情况下,通过单击向数组添加数字按钮,我希望DisplayElement2使用更新的数组重新渲染,但它没有,为什么不呢 如果单击“显示1”,然后在“显示2”上单击“上一步”,则更新后的阵列将渲染

我已经创建了一个重新渲染问题的简化版本,我正在处理一个应用程序

实际上,
displayement1
displayement2
是两个复杂的组件

displayement2
这里是通过一个简单的数字数组(通过其道具
numbers
提供)迭代并显示它们

问题:当
数字
道具后面的数组在主组件
应用程序
中更新时(在这种情况下,通过单击向数组添加数字按钮,我希望
DisplayElement2
使用更新的数组重新渲染,但它没有,为什么不呢

如果单击“显示1”,然后在“显示2”上单击“上一步”,则更新后的阵列将渲染

App.js
从“React”导入React;
从“@material ui/core”导入{Paper}”;
导出默认函数DisplayComponent2(道具){
返回(
这是DisplayComponent2

{props.number.map((currNumber,currIndex)=>{ 返回{currNumber}; })} ); }
对于你的App.js,可以考虑这样做,其中显示状态是枚举的,我们已经删除了useMoom

import React, { useState } from "react";
import "./styles.css";
import DisplayComponent1 from "./DisplayComponent1";
import DisplayComponent2 from "./DisplayComponent2";
import { Button } from "@material-ui/core";

const DisplayStatEnum = {COMPONENT1: 0, COMPONENT2: 1}; 

export default function App() {
  const [numbersToDisplay, setNumbersToDisplay] = useState([1, 2, 3]);

  ////////////////////////////////////////////////
  const component1 = <DisplayComponent1 />;

  const component2 = <DisplayComponent2
        style={{ background: "red" }}
        numbers={numbersToDisplay}
      />;
  ////////////////////////////////////////////////

  const [currentDisplayComponent, setCurrentDisplayComponent] 
    = useState(DisplayStatEnum.COMPONENT2);

  const componentSelected = 
    currentDisplayComponent === DisplayStatEnum.COMPONENT1
      ? component1
      : component2;

  return (
    <div className="App">
      <div>
      <Button
        variant="contained"
        color="secondary"
        onClick={() => setCurrentDisplayComponent(DisplayStatEnum.COMPONENT1)}
      >
        Show Display 1
      </Button>
      <Button
        variant="contained"
        color="primary"
        onClick={() => setCurrentDisplayComponent(DisplayStatEnum.COMPONENT2)}
      >
        Show Display 2
      </Button>
      </div>

      <Button
        variant="contained"
        style={{ marginLeft: 50 }}
        onClick={() => {
          let tempArray = Array.from(numbersToDisplay);
          tempArray.push(4);
          setNumbersToDisplay(tempArray);
        }}
      >
        Add number to array
      </Button>

      {componentSelected}
    </div>
  );
}
import React,{useState}来自“React”;
导入“/styles.css”;
从“/DisplayComponent1”导入DisplayComponent1;
从“/DisplayComponent2”导入DisplayComponent2;
从“@material ui/core”导入{Button}”;
const DisplayStatEnum={COMPONENT1:0,COMPONENT2:1};
导出默认函数App(){
const[numbersToDisplay,setNumbersToDisplay]=useState([1,2,3]);
////////////////////////////////////////////////
常量分量1=;
常量分量2=;
////////////////////////////////////////////////
常量[currentDisplayComponent,setCurrentDisplayComponent]
=使用状态(DisplayStatEnum.COMPONENT2);
所选常量组件=
currentDisplayComponent==DisplayStatEnum.COMPONENT1
?组件1
:组件2;
返回(
setCurrentDisplayComponent(DisplayStatEnum.COMPONENT1)}
>
显示1
setCurrentDisplayComponent(DisplayStatEnum.COMPONENT2)}
>
显示2
{
让tempArray=Array.from(numbersToDisplay);
temparay.push(4);
setNumbersToDisplay(tempArray);
}}
>
将数字添加到数组中
{componentSelected}
);
}

您的组件没有使用更新的道具重新渲染的原因是,您的组件的前一个实例存储在您用来渲染的
currentDisplayComponent
状态中

  • 使用当前代码的一个棘手的解决方法是使用useEffect并更新激活的组件实例

  • 但是,在这种情况下,最好的解决方案是将
    组件实例
    移出状态,并基于选定的组件字符串状态呈现这些实例

为了防止不必要的更新,您可以使用
React.memo

export default React.memo(function DisplayComponent2(props) {
  return (
    <Paper>
      <p>This is DisplayComponent2</p>
      {props.numbers.map((currNumber, index) => {
        return <div key={index}>{currNumber}</div>;
      })}
    </Paper>
  );
});
export default React.memo(功能显示组件2(道具){
返回(
这是DisplayComponent2

{props.number.map((currNumber,index)=>{ 返回{currNumber}; })} ); });

App.js

export default function App() {
  const [numbersToDisplay, setNumbersToDisplay] = useState([1, 2, 3]);

  const [currentDisplayComponent, setCurrentDisplayComponent] = useState(
    "component1"
  );

  const getCurrentComponent = currentDisplayComponent => {
    switch (currentDisplayComponent) {
      case "component1":
        return <DisplayComponent1 />;
      case "component2":
        return (
          <DisplayComponent2
            style={{ background: "red" }}
            numbers={numbersToDisplay}
          />
        );
      default:
        return null;
    }
  };
  return (
    <div className="App">
      <Button
        variant="contained"
        color="secondary"
        onClick={() => setCurrentDisplayComponent("component1")}
      >
        Show Display 1
      </Button>
      <Button
        variant="contained"
        color="primary"
        onClick={() => setCurrentDisplayComponent("component2")}
      >
        Show Display 2
      </Button>

      <Button
        variant="contained"
        style={{ marginLeft: 50 }}
        onClick={() => {
          let tempArray = Array.from(numbersToDisplay);
          tempArray.push(4);
          setNumbersToDisplay(tempArray);
        }}
      >
        Add number to array
      </Button>

      {getCurrentComponent(currentDisplayComponent)}
    </div>
  );
}
导出默认函数App(){
const[numbersToDisplay,setNumbersToDisplay]=useState([1,2,3]);
常量[currentDisplayComponent,setCurrentDisplayComponent]=useState(
“组件1”
);
常量getCurrentComponent=currentDisplayComponent=>{
开关(currentDisplayComponent){
案例“组件1”:
返回;
案例“组件2”:
返回(
);
违约:
返回null;
}
};
返回(
setCurrentDisplayComponent(“component1”)}
>
显示1
setCurrentDisplayComponent(“component2”)}
>
显示2
{
让tempArray=Array.from(numbersToDisplay);
temparay.push(4);
setNumbersToDisplay(tempArray);
}}
>
将数字添加到数组中
{getCurrentComponent(currentDisplayComponent)}
);
}

可能是因为您已将组件进行了记忆。有一点提示,不要将组件放在组件内部,否则React diff将失败,因为每个渲染都将有一个新的组件类。您可能已使用
useMemo
来防止这种情况发生,但这似乎非常棘手。在这种情况下,您建议的“最佳实践”方法是什么一个场景?就像一场梦。非常感谢。很高兴能帮助西蒙:-)
import React, { useState } from "react";
import "./styles.css";
import DisplayComponent1 from "./DisplayComponent1";
import DisplayComponent2 from "./DisplayComponent2";
import { Button } from "@material-ui/core";

const DisplayStatEnum = {COMPONENT1: 0, COMPONENT2: 1}; 

export default function App() {
  const [numbersToDisplay, setNumbersToDisplay] = useState([1, 2, 3]);

  ////////////////////////////////////////////////
  const component1 = <DisplayComponent1 />;

  const component2 = <DisplayComponent2
        style={{ background: "red" }}
        numbers={numbersToDisplay}
      />;
  ////////////////////////////////////////////////

  const [currentDisplayComponent, setCurrentDisplayComponent] 
    = useState(DisplayStatEnum.COMPONENT2);

  const componentSelected = 
    currentDisplayComponent === DisplayStatEnum.COMPONENT1
      ? component1
      : component2;

  return (
    <div className="App">
      <div>
      <Button
        variant="contained"
        color="secondary"
        onClick={() => setCurrentDisplayComponent(DisplayStatEnum.COMPONENT1)}
      >
        Show Display 1
      </Button>
      <Button
        variant="contained"
        color="primary"
        onClick={() => setCurrentDisplayComponent(DisplayStatEnum.COMPONENT2)}
      >
        Show Display 2
      </Button>
      </div>

      <Button
        variant="contained"
        style={{ marginLeft: 50 }}
        onClick={() => {
          let tempArray = Array.from(numbersToDisplay);
          tempArray.push(4);
          setNumbersToDisplay(tempArray);
        }}
      >
        Add number to array
      </Button>

      {componentSelected}
    </div>
  );
}
export default React.memo(function DisplayComponent2(props) {
  return (
    <Paper>
      <p>This is DisplayComponent2</p>
      {props.numbers.map((currNumber, index) => {
        return <div key={index}>{currNumber}</div>;
      })}
    </Paper>
  );
});
export default function App() {
  const [numbersToDisplay, setNumbersToDisplay] = useState([1, 2, 3]);

  const [currentDisplayComponent, setCurrentDisplayComponent] = useState(
    "component1"
  );

  const getCurrentComponent = currentDisplayComponent => {
    switch (currentDisplayComponent) {
      case "component1":
        return <DisplayComponent1 />;
      case "component2":
        return (
          <DisplayComponent2
            style={{ background: "red" }}
            numbers={numbersToDisplay}
          />
        );
      default:
        return null;
    }
  };
  return (
    <div className="App">
      <Button
        variant="contained"
        color="secondary"
        onClick={() => setCurrentDisplayComponent("component1")}
      >
        Show Display 1
      </Button>
      <Button
        variant="contained"
        color="primary"
        onClick={() => setCurrentDisplayComponent("component2")}
      >
        Show Display 2
      </Button>

      <Button
        variant="contained"
        style={{ marginLeft: 50 }}
        onClick={() => {
          let tempArray = Array.from(numbersToDisplay);
          tempArray.push(4);
          setNumbersToDisplay(tempArray);
        }}
      >
        Add number to array
      </Button>

      {getCurrentComponent(currentDisplayComponent)}
    </div>
  );
}