React Native - 仅在状态发生变化时获取输入值

发布于 2025-01-16 06:26:08 字数 3489 浏览 0 评论 0原文

我有一个非常简单的表单,包含两个元素。一个是 TextInput,另一个是 DateTimePicker。我通过点击 TouchableHighlight 列表中的一个元素来调用此表单。点击后,我发送我点击的元素的索引,并使用它从数组中获取对象。

当我打开包含输入和日期时间的编辑表单时,编辑其中任何一个并点击确认我的代码工作正常。

但是,如果在关闭此字段后,打开另一个字段并仅编辑两个字段之一,则另一个(未修改的)字段将采用状态变量中最后保存的值。这个值是之前修改的值,因为由于我没有更新这个字段,所以它的变量的状态值没有改变。

我的问题是如何避免这种情况?我怎样才能检测到哪个字段发生了变化并让其他字段保持不变。我可以创建一个状态变量,仅当字段值更改时该变量才会更改。这不是我正在寻找的解决方案,因为如果我有 100 个字段怎么办?

在我的代码下面:

//Here I get the element the user tapped. 
const element = arrayOfElems[index]


/**
These are the current values of each element. I store them here instead of in a state,
because If I always use the state if the user makes no change, then the displayed 
values are replaced for those stored in the state.
**/
const defaultName = element.name;
const defaultTime = element.time;

//A state variable to determine if any field has been modified
const [edit, setEdit] = useState(false)

//Set a state variable for the name and time values of the selected element
const [nameInState, setNameInState] = useState(defaultName)
const [timeInState, settimeInState] = useState(defaultTime)


  /** My guess is my problem is here, because no matter which field
      I modify, I set the edit state to true. It's the way I came up to
      determine if the form had been modified. If I don't do this and 
      use the setState directly in the input, then if I save with no changes,
      the values are changed to the previous saved state.**/ 
  const updateValue = (value):string | number => {
    setEdit(true)
    if (typeof value == "number"){
      settimeInState(value)
      return timeInState
    }
    setNameInState(value)
    return nameInState
  }
  
  /** If the user has made no changes, I save the default values
      instead of those in the state variables. **/
  const getValue = (type) => {
    if(type === "time"){
      return edit ? timeInState : defaultTime
    }
    return edit ? nameInState : defaultName
  }

// This is the action when the user taps confirm
const updateInfoInDb = ():void => {
    if (typeof timeInState !== "number") { return }
    appoint.editSched(index, personId, {
      name: getValue("name"),
      time: getValue("time"),
    } as IAppointm)
      .then(() => {
        doStuff()
      })
      .catch((err) => {
        setLoading(false)
      })
      setEdit(false)
  }

return(
            <View style={Modals.styles.modalBody}>
            <Input
              inputContainerStyle={Inputs.outlined}
              defaultValue={defaultName}
              onChangeText={updateValue}
              errorStyle={Inputs.errorMessage}
              />
            <Text style={Modals.styles.label} tx="en.modifyTimeDate" />
            <TimePicker programTime={getValue("time")} updateTime={updateValue} />
            <DefaultButton
              action={updateInfoInDb}
              disabled={disabled}
              disabledStyle={"disabled"}
              loading={loading}
              size={"base"}
              style={"primary"}
              text={"common.confirm"}
            />
          </View>
)

这是 的代码

<DateTimePicker
 mode="time"
 display="default"
 style={styles.androidTimePicker}
 is24Hour={is24h()}
 value={programTimeToDate}
 onChange={updateTime}/>

I have a very simple form with two elements. One is a TextInput, the other one a DateTimePicker. I call this form by tapping on one element in a list of TouchableHighlight. After tapping, I send the index of the element I tapped and use it to get the object from an array.

When I open the edit form containing an Input and a dateTime, edit any of them and tap confirm my code works fine.

However if after I close this one, I open another one and edit only one of both fields, the other (non-modified) field will take the last saved value in the state variable. This value is the value for the previous modification, because since I did not updated this field, the state value for it's variable hasn't changed.

My question is how to avoid this? How can I detect which field changed and let the other remain the same. I could create a state variable that will change only if the field value changes. That is not the solution I'm looking for because what if I have 100 fields?

Below my code:

//Here I get the element the user tapped. 
const element = arrayOfElems[index]


/**
These are the current values of each element. I store them here instead of in a state,
because If I always use the state if the user makes no change, then the displayed 
values are replaced for those stored in the state.
**/
const defaultName = element.name;
const defaultTime = element.time;

//A state variable to determine if any field has been modified
const [edit, setEdit] = useState(false)

//Set a state variable for the name and time values of the selected element
const [nameInState, setNameInState] = useState(defaultName)
const [timeInState, settimeInState] = useState(defaultTime)


  /** My guess is my problem is here, because no matter which field
      I modify, I set the edit state to true. It's the way I came up to
      determine if the form had been modified. If I don't do this and 
      use the setState directly in the input, then if I save with no changes,
      the values are changed to the previous saved state.**/ 
  const updateValue = (value):string | number => {
    setEdit(true)
    if (typeof value == "number"){
      settimeInState(value)
      return timeInState
    }
    setNameInState(value)
    return nameInState
  }
  
  /** If the user has made no changes, I save the default values
      instead of those in the state variables. **/
  const getValue = (type) => {
    if(type === "time"){
      return edit ? timeInState : defaultTime
    }
    return edit ? nameInState : defaultName
  }

// This is the action when the user taps confirm
const updateInfoInDb = ():void => {
    if (typeof timeInState !== "number") { return }
    appoint.editSched(index, personId, {
      name: getValue("name"),
      time: getValue("time"),
    } as IAppointm)
      .then(() => {
        doStuff()
      })
      .catch((err) => {
        setLoading(false)
      })
      setEdit(false)
  }

return(
            <View style={Modals.styles.modalBody}>
            <Input
              inputContainerStyle={Inputs.outlined}
              defaultValue={defaultName}
              onChangeText={updateValue}
              errorStyle={Inputs.errorMessage}
              />
            <Text style={Modals.styles.label} tx="en.modifyTimeDate" />
            <TimePicker programTime={getValue("time")} updateTime={updateValue} />
            <DefaultButton
              action={updateInfoInDb}
              disabled={disabled}
              disabledStyle={"disabled"}
              loading={loading}
              size={"base"}
              style={"primary"}
              text={"common.confirm"}
            />
          </View>
)

This is the code for the <TimePicker/>

<DateTimePicker
 mode="time"
 display="default"
 style={styles.androidTimePicker}
 is24Hour={is24h()}
 value={programTimeToDate}
 onChange={updateTime}/>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文