【问题标题】:reactjs custom component input value doesnt update with state changereactjs自定义组件输入值不会随着状态变化而更新
【发布时间】:2020-01-22 22:24:27
【问题描述】:

我正在开发一个列表应用程序,但我遇到了组件更新不正确的问题。我从 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;

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

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

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

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

    useEffect(() => {
     setProduct(props.item)
     setQuantity(props.units)
     setCart(props.cart);
    
    }, [props.item, props.units, props.cart]);
    

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

    附带说明 - 将 props 分配给 state 是一个坏主意,您已经知道原因了 - 它们不会自动更新。您应该将这些道具设置为父级的地方吊起来,您可以将它们作为道具传递并直接使用它们。您也可以将 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 稍微提升该逻辑,但我认为它会让您朝着正确的方向前进。

    【讨论】:

    • 感谢您的文章、信息和修复。当我更改值时,我将如何更新输入?这就是使用状态的最初原因,所以如果我改变了输入,那么它也会改变。
    • 用一个例子更新了我的答案。如果您需要进一步说明或有其他问题,请告诉我。
    • 如果对您有帮助,请随时将其标记为正确答案 :)
    • 我将如何处理多个不同的子组件?在我的初始代码中,我正在映射一个数组以创建特定的子代。在您的示例中,当我创建多个孩子时,它们都具有相同的“项目”状态。你也有Parent state of item - {item}。我不认识这个,也找不到有关它的信息。
    • 更新了我的答案。希望这会有所帮助。就前面提到的Parent state of item - {item} 而言,这只是我为了帮助您了解所有事物的存在而添加的一个小标签。
    猜你喜欢
    • 1970-01-01
    • 2023-01-10
    • 2023-03-08
    • 2020-09-10
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    相关资源
    最近更新 更多