reactjs 当我使用“defaultValue”赋值时,React组件从状态对象中的错误字段字段获取错误值

qgelzfjb  于 2022-11-22  发布在  React
关注(0)|答案(3)|浏览(127)

我的代码如下所示,您可以看到它在https://codepen.io/rongeegee/pen/BaVJjGO中是如何工作的:

const { useState } = React;

const Counter = () => {
  const [data, setData] = useState({
    displayData: "data_one",
    data_one: {
      text: ""
    },
    data_two:{
      text:""
    }
  })
  
  function handleOnChange(event){
    event.preventDefault();
    const new_data = {...data};
    if (event.target.name == "displayData"){
      new_data.displayData = event.target.value;
      setData(new_data);
    }
    else{
      new_data[event.target.name]["text"] = event.target.value;]
      setData(new_data);
    }
  }

  return (
    <div>
      <form onChange={handleOnChange}>
        <select name="displayData" value={data.displayData}>
          <option value="data_one">data_one</option>
          <option value="data_two">data_two</option>
        </select>
        <br/>
        {
          data.displayData == "data_one" 
            ?
            <>data One: <input name="data_one" defaultValue={data.data_one.text} /></> 
            :
            <>data two: <input name="data_two" defaultValue={data.data_two.text} /></>
        }
      </form>
    </div>
  )
}

ReactDOM.render(<Counter />, document.getElementById('app'))

如果我在data_one的输入中键入一些内容,在“data_one”和“data_two”之间切换值,data_two输入字段将具有相同的值。如果我更改data_one中的值,将下拉列表切换到“data_one”,data_one将再次具有相同的值。
这不应该发生,因为data_one input使用data state中data_one字段的文本字段的值,而data_two input使用data_two字段的文本字段的值。不应该从state中的另一个字段获取值。

vcudknz3

vcudknz31#

React有一种方法来确定哪些元素/组件已经更改,哪些没有更改。这是必要的,因为DOM操作的开销很大,所以我们应该尽可能地限制它。这就是为什么React有一种方法来确定在重新呈现之间哪些更改了,哪些没有更改;并且只更改DOM中更改的内容。
因此,如果我们在您的案例中从dataOne切换到dataTwo,React会执行类似以下操作:“哦,不错,input元素仍然是input元素。不错,我不需要完全破坏DOM节点并从头开始渲染它,我可以检查更改了什么并更改它。让我们看看:名称已经更改......所以让我们更改它,但除此之外,一切都保持不变。”(这意味着您的input元素不会被销毁,另一个元素也不会被初始渲染,但一个input元素得到的是名称更改,React就到此为止了--由于default Value仅适用于元素/DOM节点的初始创建,因此不会显示它)
React重新呈现内容和比较/修改DOM的方式相当复杂。为了获得更多信息,我可以重新播放以下视频:https://youtu.be/i793Qm6kv3U(它确实帮助我更好地理解了整个React Render过程)。
解决这个问题的一个可能的方法是给予每个输入元素一个键,这样你的输入元素看起来就像这样:

<input key="1" name="data_one" defaultValue={data.data_one.text} />
<input key="2" name="data_two" defaultValue={data.data_two.text} />

所以是的,修复相当容易;然而,理解我们为什么需要这个修复的原因并不容易。

vptzau2j

vptzau2j2#

关于你的评论(我的回答是渴望评论,格式在回答中更好)
不,你没有在输入字段改变时改变状态...你正在改变/操作状态变量data...但是你没有更新你的状态。因此没有触发重新渲染,并且如果由其他东西触发重新渲染,数据将会丢失。所以你实际上没有改变状态。
只能通过调用useState-Hook提供的回调函数来更改状态。(在您的示例中,useState-Hook提供的回调函数是setData。在您的else语句中,您没有调用提供的回调函数,而只是操作data对象(因为您进行了浅层克隆,因此操作了原始的data对象)
当改变状态时,一定要使用提供的回调函数const [stateVariable, thisIsTheCallback] = useState(initVal)。如果你不使用这个回调函数,而只是操纵stateVariable,你迟早会遇到问题(调试这个问题特别乏味,因为看起来你在改变状态(因为stateVariable改变了),但实际上你并没有改变状态,因为只有回调函数可以做到这一点)

uqzxnwby

uqzxnwby3#

defaultValue属性替换为value属性,一切都会正常。
要了解defaultValue在状态更改后无法更新的原因,请阅读**@Lord-JulianXLII**的第一个答案

相关问题