首页 > 解决方案 > React Hooks:即使我使用扩展运算符、prevState 等,状态也会重置为空数组

问题描述

简化代码示例就在这里

单词:简而言之:我的items状态正在重置为[]每点击一个新的复选框,我不明白为什么。但相反,我想使用扩展运算符和useState钩子将新项目推送到数组中,因此它是一个对象数组。

当前行为的详细信息:我正在创建一个对象并使用所有(我的意思是所有)方式的 ReactuseState钩子将其设置为状态,如下所示:setItems((prevState) => [...prevState, { [evt.target.value]: evt.target.checked }]);当我检查一个项目时,它被添加并items成为一个对象数组(它被添加到和重来一遍不是问题;稍后我会添加一个检查)。但是问题出在:当我单击一个新复选框时,items数组被设置回并没有[]与 prev 连接items——即使我正在使用prevState、spread 运算符、一个箭头函数作为包装器,以及所有这些爵士乐。

期望的行为:每次我选中一个复选框时,我都想更新items []以将一个新对象推入其中,该对象代表曾经被选中的所有项目。在您说有关复制的任何内容之前:我将添加检查以查看某个项目是否已在数组中,如果是则更新它。在我将所有内容添加items到购物车之前,我将删除所有带有checked = false状态的对象。

你能帮我理解我在这里缺少什么反应生命周期基础吗?为什么会这样?我该如何解决?

代码:发生这种情况的地方:


简化版InputComponent

const InputComponent = ({ type, itemId, handleSearchQuery, onSubmit }) => {
    const [items, setItems] = useState([]);

    const captureInput = (evt) => {
        if (evt.target.type === 'checkbox') {
            setItems((prevState) => [...prevState, { [evt.target.value]: evt.target.checked }]);
        }
    };

    const renderCheckbox = () => {
        return (
            <form>
                <input type={type} name={itemId} value={itemId} onChange={setItem} />
                <input name={itemId} type='submit' value='Add to Cart' />
            </form>
        );
    };

    return (
        <div className='input-bar'>
            {renderCheckbox()}
        </div>
    );
};

export default InputComponent;

使用此组件的位置:

import React from 'react';
import InputComponent from './InputComponent';
import './ResultsRenderer.css';

function ResultsRenderer({ data }) {
    const renderListings = () => {
        let listings = data ? data.Search : null;

        return listings
            ? listings.map((item) => {
                    return (
                        <div className='cart-row'>
                            <InputComponent type='checkbox' className='cart-checkbox' itemId={item.imdbID} />
                            <div key={item.imdbID} className={item.imdbID}>
                                <img src={`${item.Poster}`} alt={item.Title} />
                                <div>
                                    Title<em>{item.Title}</em>
                                </div>
                                <div>{item.Year}</div>
                                <em>{item.imdbID}</em>
                            </div>
                        </div>
                    );
              })
            : null;
    };

    return <>{renderListings()}</>;
}

export default ResultsRenderer;

标签: javascriptreactjsreact-hooksuse-state

解决方案


items状态做得很好,你误解了情况。

您在items内部使用 stateInputComponent并且每个listings item都有一个InputComponent,每个都有自己的items,我认为您的意思是使用Componentitems内部的 stateResultsRenderer来追逐所有 selected items

这是您需要做的更改:

const InputComponent = ({ type, itemId, setItems }) => {
  const captureInput = (evt) => {
    if (evt.target.type === "checkbox") {
      setItems((prevState) => [
        ...prevState,
        { [evt.target.value]: evt.target.checked }
      ]);
    }
  };

  return (
    <div className="input-bar">
      <form>
        <input
          type={type}
          name={itemId}
          value={itemId}
          onChange={captureInput}
        />
        <input name={itemId} type="submit" value="Add to Cart" />
      </form>
    </div>
  );
};

export default InputComponent;
function ResultsRenderer() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    console.log(items);
  }, [items]);

  const renderListings = () => {
    let listings = [
      { itemId: 1, title: "Hello" },
      { itemId: 2, title: "World" }
    ];

    return listings
      ? listings.map((item) => {
          return (
            <div className="cart-row">
              <InputComponent
                type="checkbox"
                className="cart-checkbox"
                itemId={item.itemId}
                setItems={setItems}
              />
              <div key={item.itemId} className={item.itemId}>
                <div>
                  Title<em>{item.Title}</em>
                </div>
              </div>
            </div>
          );
        })
      : null;
  };

  return <>{renderListings()}</>;
}

这是工作演示:https ://codesandbox.io/s/boring-cookies-t0g4e?file=/src/InputComponent.jsx


推荐阅读