1

我正在构建一个带有动态字段的受控表单。Parent 组件从 redux 存储中获取数据,然后使用这些值设置状态。我不想用太多的代码行,所以我把动态字段变成了一个组件。状态保留在父组件中,我使用 props 来传递 handlechange 函数。

家长:

function EditAbout(props) {
  const [img, setImg] = useState("");
  const [body, setBody] = useState(props.about.body);
  const [instagram, setInstagram] = useState(props.about.links.instagram);
  const [linkedin, setLinkedIn] = useState(props.about.links.linkedin);
  const [press, setPress] = useState(props.about.press)

  const handleSubmit = (e) => {
   // Submit the change to redux
  };

// set states with redux store
  useEffect(() => {
    setBody(props.about.body);
    setInstagram(props.about.links.instagram);
    setLinkedIn(props.about.links.linkedin);
    setPress(props.about.press);
  }, []);

  const handleChangeChild = (e, index) =>  {
    e.preventDefault();
    let articles = press
    const {value, name } = e.target
    if (name === "title") {
      articles[index].title = value;
    } else {
      articles[index].link = value;
    }
    setPress(articles)
    console.log(articles[index])
  }

  return (
    <Box>
      <h1>CHANGE ABOUT ME</h1>
      <Input
        label="Image"
        name="img"
        type="file"
        variant="outlined"
        margin="normal"
        onChange={(e) => setImg(e.target.files)}
      />
      <Input
        label="body"
        value={body}
        name="body"
        onChange={(e) => setBody(e.target.value)}
        variant="outlined"
        multiline
        rowsMax={12}
        margin="normal"
      />
      <Input
        label="instagram"
        value={instagram}
        name="instagram"
        variant="outlined"
        margin="normal"
        onChange={(e) => setInstagram(e.target.value)}
      />
      <Input
        label="Linkedin"
        value={linkedin}
        name="linkedin"
        variant="outlined"
        margin="normal"
        onChange={(e) => setLinkedIn(e.target.value)}
      />
      <Child press={press} onChange={handleChangeChild} />
      {props.loading ? (
        <CircularProgress color="black" />
      ) : (
        <Button onClick={handleSubmit} variant="contained">
          Send
        </Button>
      )}
    </Box>
  );
}

孩子 :

function Child(props) {
  const { press, onChange } = props;

  const inputsMarkup = () =>
    press.map((article, index) => (
      <div key={`press${index}`} style={{ display: "flex" }}>
        <input
          name="title"
          value={press[index].title}
          onChange={(e) => onChange(e, index)}
        />
        <input
          name="link"
          value={press[index].link}
          onChange={(e) => onChange(e, index)}
        />
        <button>Delete</button>
      </div>
    ));

  return (
    <div>
      <h1>Press :</h1>
      {inputsMarkup()}
    </div>
  );
}

当我输入父输入时,一切都很好。但是,当我对一个字符使用子字段状态更新但之后立即恢复到之前的状态时。它也不显示字符更改。我只能在控制台中看到它。提前感谢您的帮助

4

1 回答 1

2

问题是你直接改变了状态。当您创建articles变量 ( let articles = press) 时,您实际上并没有创建副本并且articles实际上不包含该值。它只是对该值的引用,它指向对象在内存中的位置。

所以当你更新articles[index].title你的handleChangeChild函数时,你实际上也在改变press状态。你可能认为这很好,但不调用setPress()React 将不会意识到变化。因此,尽管状态值发生了变化,但您不会看到它,因为 React 不会重新渲染它。

您需要press使用.map()和创建更新后的数组元素的副本来创建数组的副本。您可以在下面找到更新handleChangeChild()

const handleChangeChild = (e, index) => {
  e.preventDefault();

  const { value, name } = e.target;

  setPress(
    // .map() returns a new array
    press.map((item, i) => {
      // if the current item is not the one we need to update, just return it
      if (i !== index) {
        return item;
      }

      // create a new object by copying the item
      const updatedItem = {
        ...item,
      };

      // we can safely update the properties now it won't affect the state
      if (name === 'title') {
        updatedItem.title = value;
      } else {
        updatedItem.link = value;
      }

      return updatedItem;
    }),
  );
};

于 2020-12-09T23:33:53.500 回答