javascript 为什么将更新状态从子零部件提升到父零部件不起作用?

wdebmtf2  于 2023-01-08  发布在  Java
关注(0)|答案(2)|浏览(163)

当切换子组件的状态后尝试更新父组件的UI时,我设法达到了我想要的结果,然而,作为一个React初学者,我想我还没有完全正确地完成它。
正如您将在下面的代码中看到的,我基于event.target.value更新了单选按钮组件的状态,然后使用SitePageToggle将其提升到组件(WebsitePicker)。问题是,在我的理解中,我应该使用selectedRadioBtn的更新状态。然而,当我传递selectedRadioBtn以便根据它来建立QAObject变量的状态时,'Website'和'Page'之间的切换顺序被打乱和颠倒了。如果我在子组件本身中使用更新的状态,这就不是问题了。
我知道[state updates may be asynchronous][1],但是通过接受回调来使用useState钩子第二版也没有解决这个问题。
下面是父组件中的代码:

import styles from "./WebsitePicker.module.css";
import { useState } from "react";
import SitePageToggle from "./SitePageToggle";
import SubmitButton from "./Buttons/SubmitButton";

function WebsitePicker() {
    const [QAObject, setQAObject] = useState("Website");
    const { label, input__url } = styles;

    const toggleWebsitePageHandler = toggleData => {
        if (toggleData === 'Website') {
            setQAObject("Website");
        } else {
            setQAObject("Page");
        }
    };

    return (
        <>
            <SitePageToggle onToggle={toggleWebsitePageHandler} />
            <form onSubmit={formSubmissionHandler}>
                <label className={label} htmlFor="picker">
                    Enter the URL of the {QAObject} you wish to QA.
                </label>
                <br />
                <input
                    id="picker"
                    type="url"
                    className={input__url}
                />
                <SubmitButton>QA my page</SubmitButton>
            </form>
        </>
    );
}

export default WebsitePicker;

下面是子组件中的代码:

import RadioButton from "./Buttons/RadioButton";

function SitePageToggle({ onToggle }) {
    const [selectedRadioBtn, setSelectedRadioBtn] = useState("Website");

    const isRadioSelected = (btnValue) => selectedRadioBtn === btnValue;

    const handleToggle = event => {
        setSelectedRadioBtn(event.target.value);
        onToggle(event.target.value);
    };

return (
    <ul>
        <li>
            <RadioButton
                label="Website"
                name="react-radio-btn"
                value="Website"
                checked={isRadioSelected("Website")}
                onChange={handleToggle}
            />
        </li>
        <li>
            <RadioButton
                label="Page"
                name="react-radio-btn"
                value="Page"
                checked={isRadioSelected("Page")}
                onChange={handleToggle}
            />
        </li>
    </ul>
);
}

export default SitePageToggle;

  [1]: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
uubf1zoe

uubf1zoe1#

不确定我是否完全理解了这个用例,但是如果目标是将selectedRadioBtn的状态提升到父状态(而不是同步两个状态),那么SitePageToggle可能不需要保留状态的单独副本,而是从父状态接收状态。
快速简化演示:stackblitz
WebsitePicker中,将QAObject作为selectedRadioBtn传递:

<SitePageToggle
  selectedRadioBtn={QAObject}
  onToggle={toggleWebsitePageHandler}
/>

SitePageToggle中,使用props中的selectedRadioBtn作为状态:

import RadioButton from "./Buttons/RadioButton";

function SitePageToggle({ selectedRadioBtn, onToggle }) {
  const isRadioSelected = (btnValue) => selectedRadioBtn === btnValue;
  const handleToggle = (event) => {
    onToggle(event.target.value);
  };

  return (
    <ul>
      <li>
        <RadioButton
          label="Website"
          name="react-radio-btn"
          value="Website"
          checked={isRadioSelected("Website")}
          onChange={handleToggle}
        />
      </li>
      <li>
        <RadioButton
          label="Page"
          name="react-radio-btn"
          value="Page"
          checked={isRadioSelected("Page")}
          onChange={handleToggle}
        />
      </li>
    </ul>
  );
}

export default SitePageToggle;
jgwigjjp

jgwigjjp2#

要正确传递子状态selectedRadioBtn,应该使用useEffect()。useEffect的第二个参数是dependency数组,因此只要selectedRadioBtn发生变化,它就会触发。

import RadioButton from "./Buttons/RadioButton";

function SitePageToggle({ onToggle }) {
    const [selectedRadioBtn, setSelectedRadioBtn] = useState("Website");

    const isRadioSelected = (btnValue) => selectedRadioBtn === btnValue;

    const handleToggle = event => {
        setSelectedRadioBtn(event.target.value);
        // onToggle(event.target.value); <-- delete this here
    };

    useEffect(() => {
        onToggle(selectedRadioBtn);
    }, [selectedRadioBtn]);

    return (
        <>...</>
    );
}

相关问题