React Props 不会在子组件中更新

React Props wont update in Child Components

情况如下。

我有一个像这样的功能父组件:

function TestAutomationTab() {
  const theme = createMuiTheme({
    typography: {
      htmlFontSize: 10,
      useNextVariants: true,
    },
  });

  const [szenarios, setSzenarios] = useState([]);
  const [filterSzenario, setFilterSzenario] = useState('ALL');
  const [data, setData] = useState([{}]);
  const [runAll, setRunAll] = useState(false);
  const [runAllButton, setRunAllButton] = useState('RUN ALL');

  useEffect(() => {
    fetchDistinctSzenarios();
    fetchTestfaelle();
  }, []);

  async function fetchDistinctSzenarios() {
    const response = await Api.getDistinctTestautoSzenarios();
    setSzenarios(response.data);
    setSzenarios(oldState => [...oldState, 'ALLE']);
  }

  function handleFilterChange(event) {
    setFilterSzenario(event.target.value);
    fetchTestfaelle();
  }

  async function fetchTestfaelle() {
    const response = await Api.getAllOeTestfaelle();
    response.data.forEach((e) => {
      e.status = 'wait';
      e.errorStatus = '';
      e.statusText = '-';
    });
    setData(response.data);
  }

 function sendSingleCase(id) {
    
     data.forEach((e) => {
      if(e.id === id){
        e.status = 'sending';
      }
     })

  }

  return (
    <React.Fragment>
      <MuiThemeProvider theme={theme}>
        <div style={styles.gridContainer}>
          <Upload />
          <TestautomationSzenarioFilter
          />
          <DocBridgePieChart />
          <div style={styles.uebersicht}>
            {filterSzenario.length ? <OeTestfallAccordion
              choosenFilter={filterSzenario}
              testData={data}
              runAll={runAll}
              sendSingleCase={sendSingleCase}
            /> : <div>Wähle Szenario</div>}
          </div>
        </div>
      </MuiThemeProvider>
    </React.Fragment>
  );
}

OeTestfallAccordion

function OeTestfallAccordion(props) {
  const data = props.testData;

  return (
    <React.Fragment>
      {data.map(e => (<OeTestfall
        key={e.id}
        szenario={e.szenario}
        testid={e.testfallid}
        json={e.json}
        status={e.status}
        runAll={props.runAll}
        errorStatus={e.errorStatus}
        statusText={e.statusText}
        sendSingleCase={props.sendSingleCase}
      />))}
    </React.Fragment>
  );
}

OeTestfall

function OeTestfall(props) {
  const { szenario, testid, json } = props;
  const [open, setOpen] = useState(false);

  function handleOpen(event) {
    event.stopPropagation();
    setOpen(true);
  }

  function handleClose() {
    setOpen(false);
  }

  return (
    <ExpansionPanel>
      <ExpansionPanelSummary expandIcon={<ExpandMoreOutlined />}>
        <OeTestfallSummary
          szenario={szenario}
          testid={testid}
          json={json}
          status={props.status}
          handleClose={handleClose}
          handleOpen={handleOpen}
          open={open}
          statusText={props.statusText}
          errorStatus={props.errorStatus}
          sendSingleCase={props.sendSingleCase}
        />
      </ExpansionPanelSummary>
      <ExpansionPanelDetails>
        <div>ForNoError</div>
      </ExpansionPanelDetails>
      <ExpansionPanelActions>
        <Button
          variant="outlined"
          color="primary"
        >
            Bearbeiten
        </Button>
        <Button
          variant="outlined"
          color="secondary"
        >
            Löschen
        </Button>
      </ExpansionPanelActions>
    </ExpansionPanel>
  );
}

OeTestfallSummery

function OeTestfallSummary(props) {
  const { handleOpen } = props;

  const [status, setStatus] = useState('');
  const [statusText, setStatusText] = useState('');
  const [errorStatus, setErrorStatus] = useState('');

  useEffect(() => {
    setErrorStatus(props.errorStatus);
    setStatusText(props.statusText);
    setStatus(props.status);
  }, []);


  return (
    <div style={styles.summaryWrapper}>
      <Typography align="center" variant="subtitle1">
            TestID: {props.testid}
      </Typography>
      <Typography align="center" variant="subtitle1" style={{ fontWeight: 'bold' }}>
        {props.szenario}
      </Typography>
      <Button
        size="small"
        variant="outlined"
        color="primary"
        onClick={handleOpen}
      >
            JSON
      </Button>
      <Tooltip title="VorneTooltip" style={styles.lightTooltip} placement="left">
        <Chip
          color="secondary"
          variant="outlined"
          label={status}
        />
      </Tooltip>
      <StatusChip
        status={errorStatus}
      />
      <OeJsonViewer json={JSON.parse(props.json)} open={props.open} handleClose={props.handleClose} stopEventPropagation />
      <Tooltip
        title="ToolTipTitel"
        style={styles.lightTooltip}
        placement="top"
      >
        <Chip
          color="primary"
          variant="outlined"
          label={statusText}
        />
      </Tooltip>
      <Button variant="contained" color="primary" onClick={() => props.sendSingleCase(props.testid)} >
            Run
      </Button>
      <Button variant="contained" color="primary" onClick={() => console.log(status)} >
            test
      </Button>
    </div>
  );
}

在我的 OeTestfallAccordion 中,prop testData 没有更新。如果我尝试在我的 childComponent 中 console.log 它具有旧值,就像我执行 sendSinglecase 函数之前一样。我需要做什么,我正确地更新了数据,我的子组件收到了道具已更改并且必须重新渲染的通知。

编辑:

我尝试了一些新东西,可以缩小问题范围。在我的 TestAutomationTab 组件中,我将整个数据状态发送到 OeTestfallAccordion 子组件。在这个 OeTestfallAccordion 组件中,我拆分了由多个对象组成的数据数组,例如:

0: {id: 41, testfallid: 1, json: "{\"testCaseData\":{\"baseData\":{\"Check\":\"Thing…e\":\"alle\",\"tuwid\":\"2909\"}},\"testType\":\"Test\"}}", ID: null, businessId: null, …}
1: {id: 42, testfallid: 2, json: "{\"testCaseData\":{\"baseData\":{\"testfallid\":\"1…e\":\"alle\",\"tuwid\":\"2909\"}},\"testType\":\"Test\"}}", edcomAuftragsId: null, businessId: null, …}

当我在父组件 TestAutomationTab 中点击函数 sendSingleCase 时,我只更改了对象的一个​​参数。 Data 的整个结构保持不变。子组件无法识别我更改了数据对象中的某些内容。

但我不知道为什么?当道具更改时,我还尝试在我的子组件中使用对道具更改的影响。但即使 props.data.

中的某些属性已更新,它也永远不会执行
function OeTestfallAccordion(props) {
  const testData = props.testData;
  const [data, setData] = useState(testData);

  useEffect(() => {
    setData(testData);
    console.log("triggered");
  }, [props]);
...
}

好的,事情有点进展了。

我将 sendSingleCase 函数更改为首先将整个状态复制到 Temp 变量中。更改对象内的一个属性,然后使用 tempData 变量设置数据(在 useState 内)。因此整个状态得到更新,子组件识别出变化并重新渲染。

不过好像不是很快。总是将整个数据复制到一个新变量中,然后重新分配它是非常耗费资源的。有更好的解决方案吗?

  function sendSingleCase(id) {
    const tempState = [...data];
    tempState.forEach((e) => {
      if (e.testfallid === id) {
        e.status = "pressed";
        console.log(e.status);
      }
    });
    setData(tempState);
  }