8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

React 无法在正确的时间触发 usestate 改变

Workguy1211 2月前

27 0

我正在尝试按价格从低到高或从高到低对产品进行排序,这是我以前在 vanilla JS 中做过的事情,但这次是在 React 中。我有一个下拉列表来选择所需的顺序和实际功能

我尝试按价格从低到高或从高到低对产品进行排序,这是我以前在 vanilla JS 中做过的事情,但这次是在 React 中。我有一个下拉菜单来选择所需的顺序,实际功能可以工作,但不是我需要的方式。

在我的本地版本代码中,如果您从下拉列表中选择排序顺序,它此时不会执行任何操作,但是如果您随后按品牌或类别筛选产品,它会同时应用品牌(或类别)过滤器和所选价格排序顺序过滤器。然后,您可以从此时将排序顺序从低到高更改为高到低或反之亦然。

因此,它似乎确实正确应用了所选的排序顺序,但它只是没有在下拉菜单中选择时呈现 useState 更改,我不确定为什么。

简而言之,以下是控制排序顺序功能的位:

const [filterData, setFilterData] = useState(productDataList.products || []);

const sortItems = (e) => {
console.log('Sort');
const sortedProducts = filterData.sort((a, b) => {
  if (e.value == "LowToHigh") {
    console.log('sorted low to high');
    if (a.price < b.price) {
      return -1;
    } else {
      return 1;
    }
  } else if (e.value == "HighToLow") {
    console.log('sorted high to low');
    if (a.price > b.price) {
        return -1;
      } else {
        return 1;
      }
    }
  });
  setFilterData(sortedProducts);
};

return (

<select id="sortDropDown" onChange={(e) => sortItems(e.target)}>
    <option value="default">Sort by:</option>
    <option value="LowToHigh">Low to high</option>
    <option value="HighToLow">High to low</option>
</select>

)

希望这足以让某人帮助提供修复信息,因为我很困惑为什么从下拉列表中选择一个选项时它没有更新。

如果没有,我已经在下面为页面添加了更多代码(虽然它是一个稍微精简的版本,通常分为几个组件,我试图在下面合并它,但如果需要任何其他东西来提供帮助,请告诉我。

提前致谢。

const {useState, useEffect}  = React

const productDataList = {
  "products": [
    {
      "id": 1,
      "title": "Essence Mascara Lash Princess",
      "category": "beauty",
      "price": 9.99,
      "brand": "Essence",
      "thumbnail": "https://cdn.dummyjson.com/products/images/beauty/Essence%20Mascara%20Lash%20Princess/thumbnail.png"
    },
    {
      "id": 2,
      "title": "Eyeshadow Palette with Mirror",
      "category": "beauty",
      "price": 19.99,
      "brand": "Glamour Beauty",
      "thumbnail": "https://cdn.dummyjson.com/products/images/beauty/Eyeshadow%20Palette%20with%20Mirror/thumbnail.png"
    },
    {
      "id": 3,
      "title": "Powder Canister",
      "category": "beauty",
      "price": 14.99,
      "brand": "Velvet Touch",
      "thumbnail": "https://cdn.dummyjson.com/products/images/beauty/Powder%20Canister/thumbnail.png"
    },
    {
      "id": 4,
      "title": "Dior J'adore",
      "category": "fragrances",
      "price": 89.99,
      "brand": "Dior",
      "thumbnail": "https://cdn.dummyjson.com/products/images/fragrances/Dior%20J'adore/thumbnail.png"
    },
    {
      "id": 5,
      "title": "Dolce Shine Eau de",
      "category": "fragrances",
      "price": 69.99,
      "brand": "Dolce & Gabbana",
      "thumbnail": "https://cdn.dummyjson.com/products/images/fragrances/Dolce%20Shine%20Eau%20de/thumbnail.png"
    },
    {
      "id": 6,
      "title": "Annibale Colombo Sofa",
      "category": "furniture",
      "price": 2499.99,
      "brand": "Annibale Colombo",
      "thumbnail": "https://cdn.dummyjson.com/products/images/furniture/Annibale%20Colombo%20Sofa/thumbnail.png"
    },
  ],
  "total": 194,
  "skip": 0,
  "limit": 36
}

const App = () => {

  const [productsLimit, setProductsLimit] = useState(productDataList.limit)
  const [filterData, setFilterData] = useState(productDataList.products || []);
  const [categories, setCategories] = useState([]);
  const [brands, setBrands] = useState([]);

  useEffect(() => {
    let filteredCategories = [],
        filteredBrands = [];
        productDataList.products.forEach((product) => {
      if (!filteredCategories.includes(product.category)) {
        filteredCategories.push(product.category);
      }
      if (!filteredCategories.includes(product.brand)) {
        filteredBrands.indexOf(product.brand) == -1 && product.brand != '' && product.brand != undefined && product.brand != null ? filteredBrands.push(product.brand) : null;
      }
    });
    setCategories(filteredCategories);
    setBrands(filteredBrands);
  }, []);

  const productFilters = (products, filt) => {
    let filteredProducts = [];
    if (categories.includes(filt)) {
      filteredProducts = products.category.toLowerCase() === filt.toLowerCase();
    } else if (brands.includes(filt)) {
      filteredProducts = products.brand === filt;
    }
    return filteredProducts;
  };

  const filter = (byFilter) => {
    if (byFilter) {
      let productsData = [...productDataList.products];
      productsData = productsData.filter((filter) => {
        return productFilters(filter, byFilter);
      });
      setFilterData(productsData);
    } else {
      setFilterData(productDataList.products);
    }
  };

  const sortItems = (e) => {
    console.log('Sort');
      const sortedProducts = filterData.sort((a, b) => {
        if (e.value == "LowToHigh") {
          console.log('sorted low to high');
          if (a.price < b.price) {
            return -1;
          } else {
            return 1;
          }
        } else if (e.value == "HighToLow") {
          console.log('sorted high to low');
          if (a.price > b.price) {
              return -1;
            } else {
              return 1;
            }
        }
      });
      setFilterData(sortedProducts);
  };

  return (

    <div>
      <select id="sortDropDown" onChange={(e) => sortItems(e.target)}>
        <option value="default">Sort by:</option>
        <option value="LowToHigh">Low to high</option>
        <option value="HighToLow">High to low</option>
      </select>
      <select onChange={(e) => filter(e.target.value)}>
        <option value="Filter Categories" selected="selected">Filter by categories</option>
        {categories.map((catFilter) => (
          <option value={catFilter}>{catFilter}</option>
        ))}
      </select>
      <select onChange={(e) => filter(e.target.value)}>
        <option value="Filter Categories" selected="selected">Filter by brands</option>
        {brands.map((item) => (
          <option value={item}>{item}</option>
        ))}
      </select>
      <button onClick={filter}>Clear filter</button>
    


      <div className='products'>

        {filterData?.slice(0, productsLimit).map(product => (
          <div className='product' key={product.id}>
            <div className='productImage'>
              <img src={product.thumbnail} />
            </div>
            <div className='productInfo'>
              <div className='productTitle'>
                <div className='productBrand'>{product.brand}</div> 
                <div className='productName'>{product.title}</div>
                <div className='productName'>{product.title}</div>
              </div>
              <div className='productPrice'>Price: £{product.price}</div>
              {}
            </div>

          </div>
        ))}
      </div>
    </div>
  )
}


ReactDOM.render(<App />, document.querySelector('#root'));
.products {
  display: flex;
  flex-wrap: wrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<div id="root"></div>
帖子版权声明 1、本帖标题:React 无法在正确的时间触发 usestate 改变
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Workguy1211在本站《javascript》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 您对 React 的理解不正确。请参考下面正确的方法。

    // const [filterData, setFilterData] = useState(productDataList.products || []);
    let [orderType,setOrderType] = useState("default")
    let filterData = useMemo(()=>{
      // write your order code with orderType ...
    },[orderType])
    
    
    return (
    
    <select onChange={(e) => setOrderType(e.target)}>
        <option value="default">Sort by:</option>
        <option value="LowToHigh">Low to high</option>
        <option value="HighToLow">High to low</option>
    </select>
    
    )
    
  • 感谢@Robin Zigmond 的评论,为了更快地参考答案,我将其添加到这里。

    更改 .sort .toSorted 确实立即解决了问题。

    const sortItems = (e) => {
      console.log('Sort');
      const sortedProducts = filterData.toSorted((a, b) => {
        if (e.value == "LowToHigh") {
          console.log('sorted low to high');
          if (a.price < b.price) {
            return -1;
          } else {
            return 1;
          }
        } else if (e.value == "HighToLow") {
          console.log('sorted high to low');
          if (a.price > b.price) {
              return -1;
            } else {
              return 1;
            }
          }
      });
      setFilterData(sortedProducts);
    };
    

    其原因如下:

    sort 改变数组并返回相同的引用(请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort ),因此 React 不会“看到”任何变化。如果您不需要支持一年前左右的浏览器,最简单的解决方案是使用新的 toSorted https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted] 方法,而不是 sort

    我仍然认为适用于旧版浏览器的解决方案/解决方法会有所帮助,并且如果有添加的话我很乐意将其标记为答案,但现在感谢@Robin Zigmond 提供此解决方案。

  • 我简直不敢相信,只需将 .sort 改为 .toSorted 就能解决问题。如果有人想支持旧版浏览器,他们该怎么做?我想其他人可能会发现这一点。

返回
作者最近主题: