简体   繁体   English

为什么useState钩子不保存变量的值?

[英]Why is my useState hook not holding the value of my variable?

I have a simple form presented with a modal that is intended to update my redux store with the value typed into the textbox. 我有一个带有模式的简单表单,该模式旨在使用在文本框中键入的值来更新我的redux存储。

I'm trying to use the useState hook to set the value of the textbox on change. 我正在尝试使用useState挂钩来设置更改时文本框的值。 When printing to the console I can see that the value of my variable - "note", is the correct value. 当打印到控制台时,我可以看到我的变量“ note”的值是正确的值。 However when trying to submit and passing "note" into my updateCheckpoint function, the value is undefined. 但是,当尝试提交并将“ note”传递到我的updateCheckpoint函数时,该值是不确定的。

Additionally upon opening the dialog and submitting a second time, the note has the correct value. 此外,在打开对话框并再次提交时,注释具有正确的值。

function CompetencyCheckpoint(props)
{
    const dispatch = useDispatch();
    let [note, setNote] = useState();

    function updateCheckpoint(note){
        if(note != null){
            console.log("Here is our note : " + note);
        }else{
            console.log("oh no, we didn't get the note");
        }
    }
    console.log(note);
    return (
        <div className="checkpoint-container">
            <i className="material-icons" onClick={()=> 
                dispatch(openDialog({
                children: (
                    <React.Fragment>
                        <DialogTitle id="form-dialog-title">Add Note</DialogTitle>
                        <DialogContent>
                        <DialogContentText>
                            Enter a note.
                        </DialogContentText>
                        <TextField
                            id="filled-textarea"
                            label="New Note"
                            placeholder="Enter note here"
                            multiline
                            value={note}
                            onChange={(e) => setNote(e.target.value)}
                            margin="normal"
                            variant="filled"
                            fullWidth
                        />
                        </DialogContent>
                        <DialogActions>
                        <Button onClick={()=> dispatch(closeDialog())} color="primary">
                            Cancel
                        </Button>
                        <Button onClick={() => updateCheckpoint(note)} color="primary">
                            Add
                        </Button>
                        </DialogActions>
                    </React.Fragment>
                    )
                }))}>
                note_add
            </i>
        </div>);
}

export default (CompetencyCheckpoint);

The issue is that your JSX for the dialog content is captured at the time of opening the dialog and will not update as re-renders occur due to changing the note state. 问题在于,对话框内容的JSX是在打开对话框时捕获的,由于更改note状态而发生重新渲染,因此不会更新。 This is why @AhmadNoor's solution causes further issues -- it changes your TextField from uncontrolled to controlled, but it never receives the updated note value. 这就是@AhmadNoor的解决方案会导致更多问题的原因-它将TextField从不受控制更改为受控制,但从未收到更新的note值。

Your openDialog function should just control the open property on the Dialog. 您的openDialog函数应该只控制Dialog的open属性。 CompetencyCheckpoint should change to include the JSX of the entire Dialog directly rather than as an argument to the openDialog dispatch, so that it is included in re-renders due to changes to the note state. CompetencyCheckpoint应该更改为直接包括整个Dialog的JSX,而不是作为openDialog调度的参数,以便由于note状态的更改而将其包含在重新渲染中。

Here's one way it could work (I'm assuming in my example that these are Material-UI components): 这是它可以工作的一种方式(在我的示例中假设这些是Material-UI组件):

import React from "react";
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText,
  DialogActions,
  Button,
  TextField
} from "@material-ui/core";

function CompetencyCheckpoint(props) {
  const [open, setOpen] = React.useState(false);
  const [note, setNote] = React.useState("");

  function updateCheckpoint(note) {
    if (note != null) {
      console.log("Here is our note : " + note);
    } else {
      console.log("oh no, we didn't get the note");
    }
  }
  console.log(note);
  return (
    <div className="checkpoint-container">
      <i className="material-icons" onClick={() => setOpen(true)}>
        note_add
      </i>
      <Dialog open={open} onClose={() => setOpen(false)}>
        <DialogTitle id="form-dialog-title">Add Note</DialogTitle>
        <DialogContent>
          <DialogContentText>Enter a note.</DialogContentText>
          <TextField
            id="filled-textarea"
            label="New Note"
            placeholder="Enter note here"
            multiline
            value={note}
            onChange={e => setNote(e.target.value)}
            margin="normal"
            variant="filled"
            fullWidth
          />
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setOpen(false)} color="primary">
            Cancel
          </Button>
          <Button onClick={() => updateCheckpoint(note)} color="primary">
            Add
          </Button>
        </DialogActions>
      </Dialog>
    </div>
  );
}

export default CompetencyCheckpoint;

编辑对话框

I was able to get the code working as expected. 我能够使代码按预期工作。 I'm not sure, maybe it had something to do with the way I was using the children: keyword, I'll check the docs to see what exactly that was doing. 我不确定,也许这与我使用children:关键字的方式有关,我将检查文档以查看其确切作用。 I was following a precedent I didn't fully understand. 我遵循的是我不完全了解的先例。

Here is the solution I came up with. 这是我想出的解决方案。 Basically I just added a state variable to control weather or not the dialog should show. 基本上我只是添加了一个状态变量来控制天气,否则对话框不应该显示。 I guess this also simplifies it so that i'm not calling redux to handle the Dialog toggle. 我想这也简化了它,所以我不调用redux来处理对话框切换。

https://codesandbox.io/embed/focused-allen-cg1lq?fontsize=14 https://codesandbox.io/embed/focused-allen-cg1lq?fontsize=14

There may be further room for refactoring by making the Dialog it's own Component. 通过使对话框成为其自己的组件,可能还有更多的重构空间。

Thank you everyone who helped out, especially TJ and Ryan! 谢谢大家的帮助,尤其是TJ和Ryan!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM