【问题标题】:update function returned by useState hook not updating the valueuseState 钩子返回的更新函数不更新值
【发布时间】:2019-06-28 19:38:42
【问题描述】:

发生了一些非常奇怪的事情。我有一个状态值,定义如下:

const [heightField, setHeightField] = useState<FormField<string>>(new FormField<string>(""));

我还定义了一个useEffect hook,它与这个状态值相关联,它的定义如下:

useEffect(() => console.log('heightfield changed, hi from the useEffect hook!'), [heightField]);

此 heightField 值在文本字段中引用如下:

      <TextField
    required
    label="Height (cms)"
    margin="normal"
    variant="outlined"
    type="number"
    value={heightField.value}
    onChange={(event) => {
      setHeightField(new FormField<string>(event.target.value))
    }}
    error={heightField.error}
    helperText={heightField.errorMessage}
  />

现在,当我在文本字段中输入文本时,heightField 值会相应更新,并且 useEffect 挂钩也会被触发。

但是,当从另一个函数更新 heightField 值时,它的值不会更新,也不会触发 useEffect 挂钩。坦率地说,我不明白为什么会发生这种行为。函数如下:

const validateHeight = (heightField: FormField<string>) => {

    const heightNumber = parseInt(heightField.value);
    let error = false;
    let errorMessage = "";
    if (!heightNumber) {
      error = true;
      errorMessage = "Wrong number, please verify.";
    }
    else if (heightNumber < 0 || heightNumber > 220) {
      error = true;
      errorMessage = "Please verify the height";
    }
    const nHeightField = new FormField<string>(heightField.value, error, errorMessage);
    setHeightField(nHeightField);
  }

该函数在点击表单的提交按钮时被调用,调用时不会触发useEffect hook,也不会相应地更新heightField值

我有什么遗漏吗?为什么在使用新对象调用更新函数时这个值没有被更新?

【问题讨论】:

  • 我的猜测是 heightField 的值在渲染之间实际上是相同的,即使在验证高度之后也是如此。 const nHeightField = new FormField&lt;string&gt;(heightField.value, error, errorMessage); 在我看来很可疑。这是您编写的自定义类吗?紧接在这行之后的nHeightField 的值是多少?
  • 是的,FormField 是我创建的自定义类。执行 validateHeightField 函数后对象不同,我输入了不正确的值,因此错误属性为 true,并且出现错误消息。更新前的heightField: Object { value: "3434343434", error: false, errorMessage: "" } and nHeightField is: Object { value: "3434343434", error: true, errorMessage: "请验证高度" }

标签: reactjs react-hooks


【解决方案1】:

根据您在问题和 cmets 中告诉我们的内容,state 对象引用似乎保持不变,即使其属性已更改。尝试通过执行以下操作来创建该对象的副本:

setState({...heightField});

或者,如果您在更新之前需要之前 state 中的某些内容:

setState((prevState) => {
 const aux = {...prevState};
 aux.someProp = someOtherValue;
 return aux;
});

如果你的状态是一个对象,并且对象引用在两次渲染之间保持不变,React 会认为它没有改变并且不会更新它。因为它只比较值。如果是numberstring,它将按值进行比较,但如果是object,它将按引用进行比较,不会深入到object 属性中。

【讨论】:

  • 我会试一试的!但是,鉴于我正在创建一个新对象,引用不应该不同吗?
  • validateHeight 函数从哪里获取对象?是从国家来的吗?因为如果是,您将获得相同的引用并返回相同的引用。
  • 如果您像我在aux 示例中所做的那样传播它的道具,您将创建一个新对象,因此具有不同的引用。尝试返回一些东西。
  • 对象确实来自状态。但是,我正在创建一个新对象,其中 error 和 errorMessage 值与我通过参数获得的值不同。我还创建了一个新对象,它只有字符串 fieldValue 相同,其余部分不同。该对象在const nHeightField = new FormField&lt;string&gt;(heightField.value, error, errorMessage); setHeightField(nHeightField); 行中创建和设置
  • 传播道具没有多大意义,因为我只使用对象的字符串值,其他属性被丢弃。不过,我回家后会试一试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
  • 2020-09-02
  • 2021-02-05
  • 2020-08-20
  • 2020-04-19
  • 2019-09-15
相关资源
最近更新 更多