reactjs 如何在React组件props中获取新的state值?

34gzjxbg  于 2023-04-11  发布在  React
关注(0)|答案(2)|浏览(157)

下面有代码。

// this is a function which pass to onClick props of a button
const handleDialogClick = () => {
    setDialogOpen({
      title: "Please Choose Language You Want",
      content: (
        <TextField
          label="Text"
          select
          fullWidth
          InputLabelProps={{ shrink: true }}
          className="border-1 border-cadet-gray"
          onChange={({ target }) => {
            setPendingLanguage(target.value);
          }}
        >
          <MenuItem value="Chinese">Chinese</MenuItem>
          <MenuItem value="English">English</MenuItem>
          <MenuItem value="Japanese">Japanese</MenuItem>
        </TextField>
      ),
      onCancelClick: setDialogClose,
      onConfirmlClick: () => {
        // below will get old reference :(
        setLanguage(pendingLanguage);

        setDialogClose();
      }
    });
  };

  return (
    <div>
      <Button variant="contained" onClick={handleDialogClick}>
        click open dialog
      </Button>

      // some code here...
    </div>
  )

当状态被功能组件的属性使用时,如何获取新的状态值是一个困惑的问题。
(我知道传递一个函数到set函数可以得到旧值,但我不应该使用旧值来计算新值。
完整代码请阅读codesandbox

bvn4nwqk

bvn4nwqk1#

问题是由存储在状态中的函数引起的,例如:

onConfirmlClick: () => {
  setLanguage(pendingLanguage);
  setDialogClose();
}

当函数被存储时,pendingLanguage的当前值被保存在闭包中。整个handleDialogClick函数在每次渲染时都被重新创建,使用当前值,但由于模态是开放的,所以保存在原子中的函数不会。
我对Jotai不是很熟悉,但是我不认为在状态中保存函数是一个好方法。然而,有一个解决方案,使用ref to to当前值pendingLanguage。ref是一个对象,状态中的旧函数将指向同一个ref对象,并且您可以获得current更新的值。

const ref = useRef(pendingLanguage);

useEffect(() => {
  ref.current = pendingLanguage;
});

const handleDialogClick = () => {
  setDialogOpen({
    title: 'Please Choose Language You Want',
    content: (
      <TextField
        label="Text"
        select
        fullWidth
        InputLabelProps={{ shrink: true }}
        className="border-1 border-cadet-gray"
        onChange={({ target }) => {
          setPendingLanguage(target.value);
        }}
        defaultValue={pendingLanguage}
      >
        <MenuItem value="Chinese">Chinese</MenuItem>
        <MenuItem value="English">English</MenuItem>
        <MenuItem value="Japanese">Japanese</MenuItem>
      </TextField>
    ),
    onCancelClick: setDialogClose,
    onConfirmlClick: () => {
      setLanguage(ref.current);

      setDialogClose();
    }
  });
};
pgvzfuti

pgvzfuti2#

你可以将选择的值赋给一个在函数开头声明的临时变量。

import { useAtom } from "jotai";
import { useState } from "react";

import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import Typography from "@mui/material/Typography";
import MenuItem from "@mui/material/MenuItem";

import { openDialogAtom, closeDialogAtom } from "../stores/dialogStateAtom";

const Test = () => {
  const [language, setLanguage] = useState("none");
  const [pendingLanguage, setPendingLanguage] = useState("");
  const [, setDialogOpen] = useAtom(openDialogAtom);
  const [, setDialogClose] = useAtom(closeDialogAtom);

  const handleDialogClick = () => {
    let pending = language;
    setDialogOpen({
      title: "Please Choose Language You Want",
      content: (
        <TextField
          label="Text"
          select
          fullWidth
          InputLabelProps={{ shrink: true }}
          className="border-1 border-cadet-gray"
          onChange={({ target }) => {
            pending = target.value
            setPendingLanguage(target.value);
          }}
        >
          <MenuItem value="Chinese">Chinese</MenuItem>
          <MenuItem value="English">English</MenuItem>
          <MenuItem value="Japanese">Japanese</MenuItem>
        </TextField>
      ),
      onCancelClick: setDialogClose,
      onConfirmlClick: () => {
        // below will get old reference :(
        setLanguage(pending);

        setDialogClose();
      }
    });
  };

  return (
    <div>
      <Button variant="contained" onClick={handleDialogClick}>
        click open dialog
      </Button>

      <form className="border-1 p-5 my-4">
        <Typography
          style={{
            textAlign: "left",
            marginBottom: 16
          }}
        >
          Language: {language} / {pendingLanguage}
        </Typography>
        <TextField
          fullWidth
          label="vocabulary"
          InputLabelProps={{ shrink: true }}
        />
      </form>
    </div>
  );
};

export default Test;

相关问题