父组件中的Reaction js状态未在子组件中重新呈现

7gyucuyw  于 2022-09-21  发布在  React
关注(0)|答案(1)|浏览(183)

所以我正在试着为我的产品做一个过滤器。为此,我在一个名为Product的组件中初始化了一个状态,该组件具有所有筛选器。然后,根据名为Category的子组件中的复选框的输入,筛选器状态会更改。

以下是我的代码:

Product.jsx:

import { useState } from "react";
import Filter from "./Filter.jsx";
import styles from "../styles/products.module.css";

const products = {
  prod1: {
    id: 1,
    name: "prod1",
    category: "laptops",
    price: "80",
    description: { brand: "lenovo", processor: "intel core i7" },
  },
  prod2: {
    id: 2,
    name: "prod2",
    category: "laptops",
    price: "10",
    description: { brand: "lenovo", processor: "intel core i7" },
  },
  prod3: {
    id: 3,
    name: "prod3",
    category: "laptops",
    price: "100",
    description: { brand: "msi", processor: "intel core i5" },
  },
  prod4: {
    id: 4,
    name: "prod4",
    category: "laptops",
    price: "200",
    description: { brand: "msi", processor: "intel core i3" },
  },
  prod5: {
    id: 5,
    name: "prod5",
    category: "phones",
    price: "50",
    description: { brand: "samsung", ram: "8gb", storage: "64gb" },
  },
  prod6: {
    id: 6,
    name: "prod6",
    category: "phones",
    price: "50",
    description: { brand: "infinix", ram: "4gb", storage: "128gb" },
  },
  prod7: {
    id: 7,
    name: "prod7",
    category: "phones",
    price: "50",
    description: { brand: "oppo", ram: "8gb", storage: "256gb" },
  },
  prod8: {
    id: 8,
    name: "prod8",
    category: "accessories",
    price: "99",
    description: { type: "keyboard" },
  },
  prod9: {
    id: 9,
    name: "prod9",
    category: "accessories",
    price: "75",
    description: { type: "mouse" },
  },
};

function Products() {
  const filter = {
    laptops: {
      brand: [],
      processor: [],
    },
    phones: {
      brand: [],
      ram: [],
      storage: [],
    },
    accessories: {
      type: [],
    },
  };
  const [filterList, setFilterList] = useState(filter);
  const [category, setCategory] = useState("all");
  const [range, setRange] = useState(9999);

  const getFilterState = () => {
    return filterList;
  };
  const setFilterState = (list) => {
    setFilterList(list);
  };

  return (
    <div className={styles.productsContainer}>
      <Filter
        range={[range, setRange]}
        category={[category, setCategory]}
        getfilterList={getFilterState}
        setFilterState={setFilterState}
      />
      <table className={styles.productsListContainer}>
        <tr className={styles.tableColumn}>
          <th className={styles.tableRow}>id</th>
          <th className={styles.tableRow}>Name</th>
          <th className={styles.tableRow}>price</th>
        </tr>

        {Object.keys(products).map((key) => {
          let flag = true;
          const product = products[key];
          const categ = product.category;
          if (
            (categ === category || category === "all") &&
            product.price <= range
          ) {
            Object.entries(filter[categ]).forEach(([key, value]) => {
              if (
                !(
                  value.length === 0 || value.includes(product.description[key])
                )
              ) {
                flag = false;
              }
            });
            if (flag) {
              return (
                <tr className={styles.tableColumn} key={product.id}>
                  <td className={styles.tableRow}>{product.id}</td>
                  <td className={styles.tableRow}>{product.name}</td>
                  <td className={styles.tableRow}>{product.price}</td>
                </tr>
              );
            }
            return null;
          }
          return null;
        })}
      </table>
    </div>
  );
}

export default Products;

Filter.jsx:

import CategoryComponent from "./Category";
import styles from "../styles/filter.module.css";

function Filter({
  filters,
  dispatch,
  category,
  getfilterList: filterList,
  setFilterState: setFilterList,
  range: rangeState,
}) {
  const [Category, setCategory] = category;
  const [Range, setRange] = rangeState;

  const handleCategoryChanged = (event, categ, key) => {
    let list = filterList();
    if (list[categ][key].includes(event.currentTarget.value)) {
      list[categ][key] = list[categ][key].filter(
        (val) => val !== event.currentTarget.value
      );
    } else {
      list[categ][key].push(event.currentTarget.value);
    }
    setFilterList(list);

    if (Category !== categ) {
      setCategory(categ);
    } else {
      let flag = false;
      Object.keys(filterList()[categ]).forEach((key) => {
        const obj = filterList()[categ][key];
        if (obj.length !== 0) flag = true;
      });
      if (!flag) {
        setCategory("all");
      }
    }
  };

  const handleRangeChanged = (event) => {
    setRange(event.currentTarget.value);
  };

  return (
    <div className="filter-container">
      <h1>{Category}</h1>
      <CategoryComponent
        filterList={filterList()}
        setFilterList={setFilterList}
        category={Category}
        handleCategoryChanged={handleCategoryChanged}
        categories={{
          brand: ["lenovo", "msi", "asus"],
          processor: ["intel core i3", "intel core i5", "intel core i7"],
        }}
      >
        laptops
      </CategoryComponent>
      <CategoryComponent
        filterList={filterList()}
        setFilterList={setFilterList}
        handleCategoryChanged={handleCategoryChanged}
        category={Category}
        categories={{
          brand: ["samsung", "infinx", "oppo"],
          ram: ["8gb", "4gb", "2gb"],
          storage: ["64gb", "128gb", "256gb"],
        }}
      >
        phones
      </CategoryComponent>
      <CategoryComponent
        filterList={filterList()}
        setFilterList={setFilterList}
        category={Category}
        handleCategoryChanged={handleCategoryChanged}
        categories={{
          type: ["keyboard", "mouse", "screen"],
        }}
      >
        accessories
      </CategoryComponent>
      <div className={styles.priceRangeContainer}>
        <input
          type="range"
          min="0"
          max="9999"
          className={styles.priceRange}
          value={Range}
          onChange={handleRangeChanged}
        />
        <span>{Range}DT</span>
      </div>
    </div>
  );
}

export default Filter;

Category.jsx

import React from "react";
import { useState, useEffect } from "react";
import styles from "../styles/category.module.css";
import arrow from "../img/angle-up-solid-svgrepo-com.svg";

export default function Category({
  handleCategoryChanged,
  children,
  categories,
  category,
  filterList,
  setFilterList,
}) {
  const [hiddenClass, setHiddenClass] = useState(styles.hidden);
  const handleClick = () => {
    if (hiddenClass) setHiddenClass("");
    else setHiddenClass(styles.hidden);
  };

  return (
    <div>
      <h5>{category}</h5>
      <div onClick={handleClick} className={styles.categoryBox}>
        {children} <img style={{ width: 15 }} src={arrow} alt="" />
      </div>
      <div className={styles.hiddenScroll + " " + hiddenClass}>
        {Object.entries(categories).map(([key, value]) => {
          return (
            <div key={key}>
              <h5>{key}:</h5>
              <ul>
                {value.map((val) => {
                  console.log(filterList);
                  return (
                    <li key={val}>
                      <input
                        type="checkbox"
                        name={val}
                        id={val}
                        value={val}
                        onChange={(e) =>
                          handleCategoryChanged(e, children, key)
                        }
                      />
                      <label htmlFor={val}>{val}</label>
                    </li>
                  );
                })}
              </ul>
            </div>
          );
        })}
      </div>
    </div>
  );
}

问题是,当我运行我的程序时,当我只选中一个复选框时,状态会改变,但当我点击更多的复选框时,什么都不会改变。

编辑:
我的组件层次结构:

products.jsx
    filter.jsx
        Category.jsx

在Products.jsx中:
我有一个状态过滤器列表,其中包含我需要的所有过滤器。

const filter = {
    laptops: {
      brand: [],
      processor: [],
    },
    phones: {
      brand: [],
      ram: [],
      storage: [],
    },
    accessories: {
      type: [],
    },
  };
  const [filterList, setFilterList] = useState(filter);

在Filter.jsx中:
我有一个作为道具从Products组件传递过来的状态FilterList。
以及一个函数,用于处理来自其子组件的任何复选框更改。

const handleCategoryChanged = (event, categ, key) => {
    let list = filterList();
    //testing if the value is already in the filterList if true we remove it
    if (list[categ][key].includes(event.currentTarget.value)) {
      list[categ][key] = list[categ][key].filter(
        (val) => val !== event.currentTarget.value
      );
    } else {
      // else we add it to the list
      list[categ][key].push(event.currentTarget.value);
    }
    setFilterList(list);

Category.jsx:

在这里,我使用onChange事件创建了我的所有复选框。

但问题是,当多个复选框被更改时,我的filterList状态不会重新呈现。

6l7fqoea

6l7fqoea1#

您错过了Filter.jsx中的useState

替换

const [Category, setCategory] = category;
const [Range, setRange] = rangeState;

使用

const [Category, setCategory] = useState(category);
const [Range, setRange] = useState(rangeState);

code sandbox上可以找到一个小的工作示例

⚠️您没有提供Filter.jsx的父代,因此在本例中只有笔记本电脑品牌可以使用

相关问题