javascript - ReactJS自定义组件输入值不随状态变化而更新

标签 javascript reactjs

我正在开发一个列表应用程序,但遇到组件未正确更新的问题。我从 JSON 文件中提取用户列表并将其保存在一个状态中。我正在使用上下文将该状态和其他信息传递给我的不同组件。最小的组件是分成可编辑列表的用户项目。这里列出了我遇到问题的项目列表。

例如,我有两个不同的 JSON 文件:

    [{"userId": 81944,
        "listId": 1,
        "title": "testa",
        "items": [
            {
                "listItemId": 0,
                "product": "walnuts",
                "quantity": 1,
                "category": "Bakery",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 1,
                "product": "syrup",
                "quantity": 1,
                "category": "Beverages",
                "unit": "Each",
                "cart": true
            },
            {
                "listItemId": 2,
                "product": "cinnamon",
                "quantity": 6,
                "category": "Bakery",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 3,
                "product": "gabonzo beans",
                "quantity": 1,
                "category": "Canned Goods",
                "unit": "Each",
                "cart": true
            },
            {
                "listItemId": 4,
                "product": "diced tomatos",
                "quantity": 7,
                "category": "Produce",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 5,
                "product": "milk",
                "quantity": 1,
                "category": "Dairy",
                "unit": "Oz",
                "cart": false
            },
            {
                "listItemId": 6,
                "product": "salmon",
                "quantity": 3,
                "category": "Meat",
                "unit": "Lb",
                "cart": false
            }]},{
        "userId": 78863,
        "listId": 4,
        "title": "testd",
        "items": [
            {
                "listItemId": 0,
                "product": "half and half",
                "quantity": 1,
                "category": "Dairy",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 1,
                "product": "Blue Cheese",
                "quantity": 1,
                "category": "Dairy",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 2,
                "product": "Garlic",
                "quantity": 1,
                "category": "Produce",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 3,
                "product": "Chestnuts",
                "quantity": 1,
                "category": "Other",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 4,
                "product": "Balsamic Vinegar",
                "quantity": 1,
                "category": "Other",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 5,
                "product": "Onions",
                "quantity": 1,
                "category": "Produce",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 6,
                "product": "Flax Seed",
                "quantity": 1,
                "category": "others",
                "unit": "Each",
                "cart": false
            },
            {
                "listItemId": 7,
                "product": "Plantains",
                "quantity": 1,
                "category": "Produce",
                "unit": "Each",
                "cart": false
            }]}]

在我的应用程序中,我有一个对话框,允许我在列表之间切换。然后,我获取列表并将其传递给要在屏幕上绘制的自定义组件。

import React, {useState,useEffect} from 'react';



const Card=(props)=>{
    //console.log('prop');
    const [cart, setCart] = useState(props.cart);
    const [Product, setProduct] = useState(props.item);
    const [Quantity, setQuantity] = useState(props.units);

    // useEffect(()=>{
    //  setProduct(props.item)
    //  setQuantity(props.units)
    //  setCart(props.cart);

    // },[])
    console.log(props)
    return (
        <li key={props.value}>
            <div>
                <input type="checkbox" checked={cart} onChange={(e)=>{props.cartChange(e.target)}}/>
            </div>
            <div>
                <input id={'product '+props.value} className='update' 
                type='text' value={Product} 
                onChange={(e)=>setProduct(e.target.value)}
                 />
                <br/>
                <input id='quantityValue' className='update' 
                type='number' value={Quantity} 
                onChange={(e)=>setQuantity(e.target.value)}
                 />
                <span id='quantityType' className='update'>{props.unitType}</span>
            </div>
            <div>
                <button id='save-button' type='button' 
                onClick={(e)=>{props.change(Product,Quantity,props.value)}}>&#10003; save</button>
                <button id='delete-button' type='button'>&#10007; delete</button>
            </div>
        </li>
    )
}
export default Card;

这是调用自定义组件的代码。您将看到我从 array.map() 调用它,这些数组很好,并且其中包含正确的信息。

import React, {useContext,useEffect} from 'react';
import {DataContext} from '../../../context/test/DataContext'
import Card from './ItemCard';

const update=(x)=>{
    console.log(x)
}

const List = () =>{
    const {listId} = useContext(DataContext);
    const {userItemList} = useContext(DataContext);
    const {GetItemList} = useContext(DataContext);
    const {ListSplit} = useContext(DataContext);
    const {foundList} = useContext(DataContext);
    const {findList} = useContext(DataContext);
    const {Updater} = useContext(DataContext);
    const {cartUpdater} = useContext(DataContext);
    useEffect(()=>{
        GetItemList();
    },[listId])
    useEffect(()=>{
        ListSplit();
    },[userItemList])
    // console.log(findList);
    // console.log(foundList);

    return(
        <div>
            <p>To find:</p>
            <ul>
            {findList.map((item,index)=><Card key={item.listItemId} index={index}
                value={item.listItemId} cart={item.cart} item={item.product} 
                units={item.quantity} unitType={item.unit} 
                cartChange={cartUpdater} change={Updater} />)}
            </ul>
            <p>Found:</p>
            <ul>
            {foundList.map((item,index)=><Card key={item.listItemId} index={index}
                value={item.listItemId} cart={item.cart} item={item.product} 
                units={item.quantity} unitType={item.unit} 
                cartChange={cartUpdater} change={Updater} />)}
            </ul>
        </div>
    )
}
export default List;

每次我切换此选项时,我控制台注销的 Prop 都会正确更改。另外,如果我在开发工具(chrome)中查看我的组件,我会发现状态应该是正确的,但是我在屏幕上看到的内容不正确。例如,第二个项目是肉桂,如果我切换到第二个列表,则应该是蓝纹奶酪。 Prop 发生了变化,状态也发生了变化,但我在屏幕上看到的仍然是肉桂色。

我知道我可能没有解释清楚,但下面是我正在谈论的内容的屏幕截图。

enter image description here

最佳答案

您已接近注释掉的代码。由于您将 props 设置为 state(这是一个坏主意,我将在底部讨论),因此您的 useState 仅最初设置状态。您想要观看这些 Prop 并在它们更新时进行更新。

useEffect(() => {
 setProduct(props.item)
 setQuantity(props.units)
 setCart(props.cart);

}, [props.item, props.units, props.cart]);

useEffect 会监视数组中的项目,以了解它是否应该触发。

顺便说一句 - 将 props 分配给 state 是一个坏主意,你已经知道为什么了 - 它们不会自动更新。您应该将这些 Prop 设置为父级的位置提升,并且可以将它们作为 Prop 传递下来并直接使用它们。您也可以将 setter 作为 props 传递下去,这可以更新父级。

This article ,而如果您愿意阅读的话,引用基于类的 React 组件可能会提供更多信息。

const { useState } = React;

const initialItems = [
  {
    listItemId: 1,
    product: 'syrup',
    quantity: 1,
    category: 'Beverages',
    unit: 'Each',
    cart: true,
  },
  {
    listItemId: 2,
    product: 'cinnamon',
    quantity: 6,
    category: 'Bakery',
    unit: 'Each',
    cart: false,
  },
  {
    listItemId: 3,
    product: 'garbanzo beans',
    quantity: 1,
    category: 'Canned Goods',
    unit: 'Each',
    cart: true,
  },
];

const Parent = () => {
  const [items, setItems] = useState(initialItems);

  const updateProduct = listItemId => (e) => {
    setItems(items.map((item) => {
      if (item.listItemId === listItemId) {
        return { ...item, product: e.target.value };
      }

      return item;
    }));
  };

  const updateQuantity = listItemId => (e) => {
    setItems(items.map((item) => {
      if (item.listItemId === listItemId) {
        return { ...item, quantity: e.target.value };
      }

      return item;
    }));
  };

  return (
    <div>
      <div style={{ width: "50%" }}>
        All Items - (this state lives inside the parent component)
      </div>
      <div>
        {items.map(item => (
          <div>
            <div>
              Product - {item.product}
            </div>
            <div>
              Quantity - {item.quantity}
            </div>
          </div>
        ))}
      </div>
      <div style={{ width: "50%" }}>
        {items.map(item => (
          <Child item={item} updateQuantity={updateQuantity} updateProduct={updateProduct} />
        ))}
      </div>
    </div>
  );
};

const Child = ({ item, updateQuantity, updateProduct }) => {
  return (
    <div>
      <div>
        <span>
          Product -
        </span>
        <span>
          <input value={item.product} onChange={updateProduct(item.listItemId)} />
        </span>
      </div>
      <div>
        <span>
          Quantity -
        </span>
        <span>
          <input value={item.quantity} onChange={updateQuantity(item.listItemId)} />
        </span>
      </div>
    </div>
  );
};

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

上面的一个小例子。父组件保存项目的状态并映射每个项目以创建子组件。这个例子的边缘有点粗糙。您可以执行一些操作,例如向每个输入添加 data-idname 来简化更新功能,或者使用 useReducer 稍微提升该逻辑,但我认为它会让你朝着正确的方向前进。

关于javascript - ReactJS自定义组件输入值不随状态变化而更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59869125/

相关文章:

javascript - react-transform-catch-errors 看起来不像 React 组件

reactjs - 如何使用 React Hooks 获取另一个组件中表单的输入值

javascript - 禁用按钮,单击另一个按钮后启用按钮

javascript - knockout : Change the color of selected value in dropdown list

javascript - 无法找到/或实现正确的 mongoDb 方法来查找和更新子文档

javascript - 如何监听 backbone 中的 HTTP 事件

javascript - 正确调用/获取信息

reactjs - 如何键入一个接受另一个组件作为 Prop 的 React 组件,以及该组件的所有 Prop ?

javascript - jQuery .load 问题。不受父 javascript 文件影响

reactjs - @react-pdf/渲染器。如何生成PDF并下载