【问题标题】:Update parent component from child when child unmounts子卸载时从子组件更新父组件
【发布时间】:2021-02-27 12:06:30
【问题描述】:

我有一个包含子数组的父组件,每次单击下一个按钮时都会显示下一个子组件。

const SqlSchema = () => {
  const [activeStep, setActiveStep] = useState(0);
  const [stepResponse, setStepResponse] = useState();
  const steps = ['Connect', 'Define tables', 'Define hierarchy', 'Finish']; 

  const getStepContent = (step) => {
    switch (step) {
      case 0:
        return <ConnectToDB onSubmit={setStepResponse} />;
      case 1:
        return <DefineTables data={stepResponse.data} onSubmit={setStepResponse} />;
      case 2:
        return <DefineHierarchy data={stepResponse.data} onSubmit={setStepResponse} />;
      case 3:
          return <Finish data={stepResponse.data} onSubmit={setStepResponse} />
    }
  };

  const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
  };

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1);
  };

  return (
     <Stepper activeStep={activeStep}>
        {steps.map(label => (
            <Step key={label}>
              <StepLabel>{label}</StepLabel>
            </Step>
        ))}
      </Stepper>

      <div>
        {activeStep === steps.length ? (
          <Typography className={classes.instructions}>
            All steps completed - you&apos;re finished
          </Typography>
        ) : (
          <div>
            <Typography>{getStepContent(activeStep)}</Typography>
            <div>
              <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
                Back
              </Button>
              <Button onClick={handleNext} className={classes.button}>
                {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
              </Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

每个孩子都获得 data 和 onSubmit 道具,并根据 data 道具管理自己的状态。 我想在单击下一个按钮时使用子状态执行 onSubmit 道具,并使用子状态更新父数据并将其发送给下一个子。 我试图在每个孩子身上做这样的事情:

const [value, setValue] = useState(props.data);
useEffect(() => {
  return () => props.onSubmit(value);
}, []);

但我发送的是初始状态而不是更新状态。 如果我将“值”添加到 useEffect 中的依赖项数组中,则会在每个 setValue 上调用 onSubmit,我不希望这样。 有没有办法仅在父级中单击“下一步”按钮时从子级获取更新状态?

【问题讨论】:

  • 保持父状态与当前子组件同步有什么问题吗?这你首先提升状态的真正原因,并且还希望有一个单一的事实来源(基本上有助于避免像你已经和正在尝试解决的状态同步问题)。
  • @DrewReese 每当更改孩子时更改父状态是否有意义?它会在其后代中的每一个微小变化时触发父级的重新渲染。
  • 是的,完全正确。通常将“通用”状态存储在一个通用的、可访问的位置,即父组件并传递给每个子组件,在 React 上下文中并由子组件、应用程序范围的状态管理(redux、mobx 等)和订阅.这里的共同点是具有单一的事实来源,应用程序只需要在一个位置更新“状态”。如果您希望其他子级在父级重新渲染时重新渲染,那么,React 有相应的工具/模式。无论如何,如果您想在子组件卸载时保持并更新父状态,请使用@thedude 的解决方案

标签: reactjs react-hooks use-effect


【解决方案1】:

我不得不说这似乎是一个奇怪的设计选择,但您可以使用ref 来跟踪当前值:

const [value, setValue] = useState(props.data);
const valueRef = useRef(value)

useEffect(() => {
    valueRef.current = value
}, [value])

useEffect(() => {
  return () => props.onSubmit(valueRef.current);
}, []);

【讨论】:

  • 您对设计有更好的想法吗?
  • 视情况而定 - 请注意,在您的实现中,当用户导航返回时,他不会返回到与已卸载步骤相同的状态。另一种方法是在只有 1 个可见的情况下渲染所有步骤,这样当用户导航时它们的状态就会持续存在
猜你喜欢
  • 1970-01-01
  • 2023-02-20
  • 1970-01-01
  • 2019-03-11
  • 2022-01-13
  • 1970-01-01
  • 2018-04-18
  • 2017-05-03
  • 2019-12-18
相关资源
最近更新 更多