axios 如何在Reactjs中更新状态?

cigdeys3  于 2023-06-22  发布在  iOS
关注(0)|答案(2)|浏览(144)

我需要帮助理解为什么在React Developer Tools状态下更新状态,而不是在i console.log时更新。下面是代码:

const [values, setValues] = useState({
    lastName: "",
    firstName: "",
    lastNameHiragana: "",
    firstNameHiragana: "",
    birthday: "",
    sex: "男",
    telephone: "",
    email: "",
    enterDate: "",
    companyId: "securityInt(SECI)",
    departmentId: "dev",
    commissionStatusId: "somestring",
    houseStatusId: "somestring",
    businessManager: "",
  });

  const onChange = (e) => {
    setValues({ ...values, [e.target.name]: e.target.value });
  };

  const handleForm = (e) => {
    e.preventDefault();

    const data = {
      firstName: values.firstName,
      lastName: values.lastName,
      firstNameHiragana: values.firstNameHiragana,
      lastNameHiragana: values.lastNameHiragana,
      companyId: values.companyId,
      birthday: values.birthday,
      sex: values.sex === "somestring" ? 0 : 1,
      mail: values.email,
      telephone: values.telephone,
      enterDate: values.enterDate,
      departmentId: values.departmentId,
      commissioningStatusId: values.commissionStatusId === "somestring" ? 0 : 1,
      houseStatusId: values.houseStatusId,
      businessManager: values.businessManager,
    };

    const newErrorMessage = {};
    const refresh_token = localStorage.getItem("refresh_token");
    const headers = {
      headers: {
        Authorization: `Bearer ${refresh_token}`,
      },
    };

    for (const name in values) {
      const hiraganaRegex = /^[ぁ-ん]+$/;
      const telephoneRegex = /^[0-9]{9,11}$/;
      const emailRegex = /^[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,4}$/;

      switch (name) {
        case "lastName":
        case "firstName":
        case "birthday":
        case "enterDate":
          if (!values[name]) {
            newErrorMessage[name] = "必須項目です";
          }
          break;

        case "lastNameHiragana":
        case "firstNameHiragana":
          if (!values[name]) {
            newErrorMessage[name] = "必須項目です";
          } else if (!hiraganaRegex.test(values[name]) && values[name]) {
            newErrorMessage[name] = "ひらがなで入力して下さい。";
          }
          break;

        case "telephone":
          if (!values[name]) {
            newErrorMessage[name] = "必須項目です";
          } else if (!telephoneRegex.test(values[name]) && values[name]) {
            newErrorMessage[name] = "9~11桁の半角数字で入力して下さい";
          }
          break;

        case "email":
          if (!values[name]) {
            newErrorMessage[name] = "必須項目です";
          } else if (!emailRegex.test(values[name]) && values[name]) {
            newErrorMessage[name] = "メールアドレスの形式が正しくありません";
          }
          break;
      }
    }
    if (!Object.keys(newErrorMessage).length) {
      // Get companies ID
      const fetchData = async () => {
        if (
          typeof values.companyId === "string" &&
          typeof values.departmentId === "string"
        ) {
          const [companyRes, departmentRes] = await Promise.all([
            axiosInstance.get("/company"),
            axiosInstance.get("/department"),
          ]);

          const company = values.companyId.slice(
            0,
            values.companyId.indexOf("(")
          );
          const findCompany = companyRes.data.result.find(
            (item) => item.name === company
          );
          const findDepartment = departmentRes.data.result.find(
            (item) => item.name === values.departmentId
          );
          console.log(values.companyId);
          console.log(values);
          setValues((prevValues) => ({
            ...prevValues,
            companyId: findCompany.id,
            departmentId: findDepartment.id,
          }));
          console.log(values.companyId);
        }
      };

      // Send the information to server
      const sendData = async () => {
        try {
          const response = await axiosInstance.post("/employee", data, {
            headers: headers,
          });

          console.log(response);
        } catch (error) {
          console.log(error);
        }
      };

      // Call the functions in sequence
      (async () => {
        await fetchData();
        await sendData();
      })();
    }

    setErrorMessage(newErrorMessage);
  };

我需要发送正确的companyIddepartmentID,当我检查React Developer Tools状态时,这是可以的,但是当我console.logvalues时,它给我的不是想要的结果。下面是不是不工作了,为什么?

setValues((prevValues) => ({
       ...prevValues,
       companyId: findCompany.id,
       departmentId: findDepartment.id,
}));

密码有什么问题吗?任何输入都将是有帮助的。
先谢谢你。

b5buobof

b5buobof1#

在React中,useState中的setValues函数是异步的,这意味着它将状态更新安排在下一次渲染时进行,而不是立即进行。因此,如果您尝试在使用setValues更新状态后立即记录它,您可能会遇到以前的状态,而不是更新后的状态。
然而,在React Developer Tools中,状态是在完成所有更新和重新渲染之后显示的。因此,即使console.log可能会显示以前的状态,React开发人员工具也会正确显示更新后的状态。
可以在代码中观察到此行为:

setValues((prevValues) => ({
    ...prevValues,
    companyId: findCompany.id,
    departmentId: findDepartment.id,
}));
console.log(values.companyId);

这里,由于setValues的异步特性,console.log(values.companyId);在状态更新之前被执行。
要解决这种情况,可以使用useEffect钩子,它在函数组件中启用副作用,并在特定值更改时执行操作。以下是您可能使用它的方式:

useEffect(() => {
  console.log(values.companyId);
}, [values.companyId]); // This effect runs whenever `values.companyId` changes

这个useEffect钩子将在companyId发生变化时记录它,因此总是反映最新的值。
此外,您的sendData函数正在使用data对象,该对象是在调用fetchData并更新状态之前定义的。您应该在sendData函数中定义data,以确保使用更新后的状态:

const sendData = async () => {
  const data = {
    firstName: values.firstName,
    lastName: values.lastName,
    firstNameHiragana: values.firstNameHiragana,
    lastNameHiragana: values.lastNameHiragana,
    companyId: values.companyId,
    birthday: values.birthday,
    sex: values.sex === "somestring" ? 0 : 1,
    mail: values.email,
    telephone: values.telephone,
    enterDate: values.enterDate,
    departmentId: values.departmentId,
    commissioningStatusId: values.commissionStatusId === "somestring" ? 0 : 1,
    houseStatusId: values.houseStatusId,
    businessManager: values.businessManager,
  };

  try {
    const response = await axiosInstance.post("/employee", data, {
      headers: headers,
    });

    console.log(response);
  } catch (error) {
    console.log(error);
  }
};

现在,如果您将data对象放在sendData函数中,则在调用该函数时,它将始终使用当前状态。
但是,请注意,由于useState钩子的异步特性,在调用sendData时状态可能不会立即更新,这可能导致data对象没有更新的值。
更好的方法是从fetchData函数返回更新后的状态,并将其作为参数传递给sendData函数。下面是如何做到这一点:

const fetchData = async () => {
  if (
    typeof values.companyId === "string" &&
    typeof values.departmentId === "string"
  ) {
    const [companyRes, departmentRes] = await Promise.all([
      axiosInstance.get("/company"),
      axiosInstance.get("/department"),
    ]);

    const company = values.companyId.slice(
      0,
      values.companyId.indexOf("(")
    );
    const findCompany = companyRes.data.result.find(
      (item)

 => item.name === company
    );
    const findDepartment = departmentRes.data.result.find(
      (item) => item.name === values.departmentId
    );

    const newValues = {
      ...values,
      companyId: findCompany.id,
      departmentId: findDepartment.id,
    };

    setValues(newValues);

    return newValues;
  }
};

const sendData = async (data) => {
  try {
    const response = await axiosInstance.post("/employee", data, {
      headers: headers,
    });

    console.log(response);
  } catch (error) {
    console.log(error);
  }
};

(async () => {
  const newValues = await fetchData();
  sendData(newValues);
})();

在此调整后的代码中,newValues存储更新后的状态,我们将其直接传递给sendData,确保sendData使用正确的更新状态。

zzoitvuj

zzoitvuj2#

“useState”set方法是异步的,因此,更新不会立即反映出来。您可以read this以获得更清晰的效果。
因为你使用的是钩子,在你的例子中你需要使用Effect钩子来查看状态中的实际值。您可以关注this answer

相关问题