反应输入值不会在按钮更改时重新呈现

Posted

技术标签:

【中文标题】反应输入值不会在按钮更改时重新呈现【英文标题】:React input value not re-rendering on button change 【发布时间】:2021-08-28 03:26:28 【问题描述】:

我正在构建一个购物车项目。

我正在尝试为我的购物车页面构建的功能之一是显示购物车中每个产品的数量的输入值(以便用户可以手动调整产品数量)以及两侧的按钮将输入的数量减少/增加 1。

这是我的代码框的链接,可以通过将任何项目之一添加到购物车来重新创建问题:

https://codesandbox.io/s/yqwic

我为手动调整输入字段而构建的逻辑按预期工作,但是当我单击递增/递减按钮时,它只会调整导航栏中显示的购物车中的项目数。输入字段没有更新 - 但是在查看 React-Developer-Tools 组件调试器时,基础数量正在更新到正确的数字 - 它只是没有重新渲染 DOM 中的输入值。

谁能指出我可能出错的地方?我尝试在输入字段中将 defaultValue 切换为 value 但这会阻止我手动调整输入。

谢谢

【问题讨论】:

【参考方案1】:

你需要做两件事,

<Quantity type='number' min='1' value=quantity ref=itemRef onChange=handleChange />

    添加 value 属性以使您的输入与您的上下文值保持同步。

    将 onBlur 替换为 onChange 。您需要这样做以确保更改输入中的值会更新您的上下文值。

【讨论】:

谢谢。有没有理由不能使用 onBlur 来实现您的第二点? 我想我刚刚从 react 提供的错误中理解了原因:Warning: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`. 然而,react 还建议我应该同时使用valuedefaultValue - arning: styled.input contains an input of type number with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://reactjs.org/link/controlled-components 对,您不能在输入中同时指定defaultValuevalue 属性。 你应该在这里使用 value 并且可以安全地删除 defaultValue 。而且由于您的组件与 context 中的值同步。 onBlur 只会在组件失去焦点时触发。因此,如果您从 1-5 更改并单击外部,您将使用最终值 - 5 触发调度,并且从 1-4 更改的值不会反映在 UI 中,因为您没有调度。所以这里需要onChange 来捕获您的每一个更改事件。【参考方案2】:

问题

    您正在严重改变 AppLogic 实用程序中的购物车项目状态。 您正在为手动输入呈现“不受控制”的输入。这意味着它最初使用一个值呈现,但是当您从外部更改“状态”时,该值表示它不会更新,因为它不受控制。

解决方案

AppLogic.js

修复您的减速器实用程序,使其不会改变购物车项目。更新它们时,您应该浅层复制整个购物车项目数组,然后浅层复制特定的购物车项目。

export const checkIfItemInCart = (item, array, sum) => 
  const index = array.findIndex((object) => object.id === item.id);
  if (index !== -1) 
    const newArray = array.map((item, i) => i === index ? 
      ...item,
      quantity: item.quantity + (sum === "add" ? 1 : -1)
     : item)
    if (!newArray[index].quantity) 
      return deleteItemLookup(item, newArray);
    
    return newArray;
  
  return array.concat(item);
;

export const customQuantityUpdate = (item, array, newQuantity) => 
  const index = array.findIndex((object) => object.id === item.id);

  const oldQuantity = array[index]?.quantity;

  // This could be more DRY, but edited to work
  if (newQuantity > oldQuantity) 
    return  array: array.map((item, i) => i === index ? 
      ...item,
      quantity: newQuantity
     : item), type: "add", newQuantity, oldQuantity ;
   else if (newQuantity < oldQuantity) 
    return  array: array.map((item, i) => i === index ? 
      ...item,
      quantity: newQuantity
     : item), type: "subtract", newQuantity, oldQuantity ;
   else 
    return  array, type: "", newQuantity, oldQuantity ;
  
;

CartItem.js

使用value 属性和onChange 属性将输入转换为完全受控的输入。

<Quantity
  type="number"
  min="1"
  value=quantity
  ref=itemRef
  onChange=handleChange
/>

演示

【讨论】:

谢谢德鲁。这是我第一次与useReducer 合作,我很高兴你接受了它。我会审查并解决。 只是一些 cmets 来跟进第一部分:如果项目不在数组中,const index = array.findIndex((object) =&gt; object.id === item.id); 返回 undefined 而不是 -1。此外,我需要将 `if (!newArray[index].quantity)` 更改为 `if (!newArray[index]?.quantity)` 以防止引发未定义的错误。我仍在努力完成剩下的工作。 @LearningPython Array.prototype.findIndex 如果没有元素与谓词匹配,肯定会返回 -1。 developer.mozilla.org/en-US/docs/Web/javascript/Reference/… Array.prototype.find 可以返回 undefined。不过,您对第二位绝对正确,在访问属性之前应该对newArray[index] 进行空检查。更新了我的答案。 好地方,我错误地使用了find 而不是findIndex。谢谢。 @LearningPython 我不知道您是否使用与我不同的浏览器,但我无法重现完全删除输入中的值。尽管如此,如果您能够以某种方式输入除数字以外的其他内容(这会导致错误的NaN)或小于最小值的值,则可以在onChange 处理程序中使用const newQuantity = Math.max(1, Number(e.target.value) || 1); 强制执行最小值。我更新了我的代码框。

以上是关于反应输入值不会在按钮更改时重新呈现的主要内容,如果未能解决你的问题,请参考以下文章

React 页面不会在 url 查询更改时重新呈现

React页面不会在url查询更改时重新呈现

React 组件不会在值更改时重新渲染并显示 CSS 更改

反应数组的对象更改顺序的更改值

属性更改时如何重新渲染反应组件

嵌套反应路由器组件不会在页面重新加载时加载/渲染?