使用ReactContext API过滤时丢失下拉选择选项 [英] Losing dropdown select options upon filtering using react context api

查看:100
本文介绍了使用ReactContext API过滤时丢失下拉选择选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我两周前才开始学习React,所以我仍然发现一些概念很困难.我从构建CRA到将其转换为NextJS并选择使用带有钩子的上下文API进行状态管理.我现在正在使用下拉列表过滤列表中的文章.当我选择某种类型的文章时,列表会正确过滤,但是当我返回到下拉列表时,只有原始选项和当前选项一起出现.当我单击原始选项时,所有列表项都消失了.我想防止下拉菜单中的选项发生变化,同时还允许过滤与设置其他过滤器同时进行(例如按城市对过滤器和按文章功能对过滤器进行设置).

I just started learning React 2 weeks ago so I am still finding some concepts difficult. I went from building a CRA to converting it to NextJS and opting for using context API with hooks for state management. I am working on filtering right now for a list of articles using a dropdown. When I select a certain type of article, the list filters correctly, but as I go back to the dropdown, only the original option is there along with the current option. When I click on the original option, all the list items disappear. I want to prevent the options in the dropdown from changing while also allowing the filtering to work at the same time as other filters are being set (e.g. sort filter by city AND filter by article feature).

在我的代码中,我正在努力使Market/Markets下拉列表正常运行.

In my code, I am struggling with getting the market/markets dropdown to function correctly.

这是我的context.js

This is my context.js

import React, { useState, useReducer, createContext } from "react";
import { articles } from "./data";

// Create Context Object
const StateContext = React.createContext([{}, () => {}]);

// Create a provider for components to consume and subscribe to changes
const StateProvider = (props) => {
  const [state, setState] = useState({
    list: articles,
    market: "All",
    isLoading: true,
  });

  return (
    <StateContext.Provider value={[state, setState]}>
      {props.children}
    </StateContext.Provider>
  );
};

export { StateContext, StateProvider };

FilterControls.js:

FilterControls.js:

import React from "react";

import useFilter from "../hooks/useFilter";

const Controls = () => {
  const { allEntries, market, handleChange } = useFilter();

  //   get all unique values
  const getUnique = (items, value) => {
    return [...new Set(items.map((item) => item[value]))];
  };
  let markets = getUnique(allEntries, "market");
  //   add all
  markets = ["All", ...markets];
  //   map to jsx
  markets = markets.map((item, index) => {
    return (
      <option value={item} key={index}>
        {item}
      </option>
    );
  });

  return (
    <>
      <div>
        <section className="filter-container">
          {/* select market */}
          <div className="form-group">
            <label htmlFor="market">Housing Market</label>
            <select
              name="market"
              id="market"
              value={market}
              className="form-control drop-down"
              onChange={handleChange}
            >
              {markets}
            </select>
          </div>
          {/* end of select market */}
        </section>

useFilter.js:

useFilter.js:

import { useContext } from "react";
import { StateContext } from "../context";

const StateFilter = () => {
  const [state, setState] = useContext(StateContext);

  let allEntries = formatData(state.list);
  let featuredEntries = allEntries.filter((e) => e.featured === true);
  let percentageOffMax = Math.max(
    ...allEntries.map((item) => item.percentageOff)
  );
  let avgppMax = Math.max(...allEntries.map((item) => item.avgpp));

  function formatData(items) {
    let tempItems = items.map((e) => {
      let id = e.id;
      let images = e.images;
      let singleEntry = { ...e, images, id };
      return singleEntry;
    });
    return tempItems.sort((a, b) => a.avgpp - b.avgpp);
  }

  function sortFromHighestToLowestPrices(items) {
    let tempItems = items.map((e) => {
      let id = e.id;
      let images = e.images;
      let singleEntry = { ...e, images, id };
      return singleEntry;
    });
    return tempItems.sort((a, b) => b.avgpp - a.avgpp);
  }
  let highestToLowest = sortFromHighestToLowestPrices(state.list);

  //   console.log(state.market);
  //   console.log(state);

  //   console.log(allEntries.filter((e) => e.market === "Homeowners"));
  function handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = event.target.name;

    console.log(value);
    let ftest = allEntries.filter((e) => e.market === value);

    setState((state) => ({ ...state, list: ftest, [name]: value }));

    // state.filterItems();
    // setState((state) =>({...state.market}))
    //   {
    //     [name]: value,
    //   },
    //   this.filterItems
    // );
    console.log(state);
  }
  // allEntries.filter((e) => e.market === value);

  function filterItems() {
    console.log(state.list);
    let { allEntries } = state.list;

    // let tempEntries = [...allEntries].sort((a, b) => b.avgpp - a.avgpp);
    // if (market !== "All") {
    //   tempEntries = tempEntries.filter((e) => e.market === market);
    // }
  }
  console.log(filterItems());

  return {
    isLoading: state.isLoading,
    allEntries,
    featuredEntries,
    sortedEntries: allEntries,
    percentageOff: percentageOffMax,
    percentageOffMax,
    avgppMax,
    handleChange,
    filterItems,
  };
};

export default StateFilter;

以及显示所有内容的articles.js:

And articles.js where everything is displayed:

import React, { useContext } from "react";
import Entry from "../components/Entry";
import Title from "../components/Title";
import { StateContext } from "../context";

import FilterControls from "../components/FilterControls";
import useFilter from "../hooks/useFilter";

const FullList = () => {
  const { allEntries, showAdelphi, isLoading } = useFilter();
  return (
    <>
      <section className="all-entries">
        <Title title="Featured Entries" />
        <FilterControls />
        <div className="all-entries-center">
          {allEntries.map((e) => (
            <Entry key={e.id} entry={e} />
          ))}
        </div>
      </section>

推荐答案

之所以不起作用,是因为没有创建临时列表.因此,当一个选项被选中时,状态被一个没有其他项的状态所代替.由于下拉菜单是该状态的结果,因此随着原始列表中项目的数量减少,选项消失了.

The reason this was not working was because there was no temporary list created. Therefore, when an option item was selected, the state was being replaced with one that didn't have the other item(s). Since the dropdown is feeding off of the state, the options disappear as the number of items in the original list are reduced.

要解决此问题,我创建了一个临时列表,该列表将根据过滤器集进行调整,同时保留原始列表以供参考.

To resolve this issue, I instead created a temporary list that would be adjusted based on the filters set while preserving the original list for reference.

排序后的列表现在是在我的文章页面上显示该列表的列表:

The sorted list is now the one that displays the list in my articles page:

<section className="all-entries">
        <Title title="Featured Entries" />
        <FilterControls />
        <div className="all-entries-center">
          {state.sortedList.map((e) => (
            <Entry key={e.id} entry={e} />
          ))}
        </div>
      </section>

现在,在我的过滤器控件中,市场从原始列表中拉出:

And now, in my filter control, the markets are pulled from the original list:

 let markets = getUnique(list, "market");
  //   add all
  markets = ["All", ...markets];
  //   map to jsx
  markets = markets.map((item, index) => {
    return (
      <option value={item} key={index}>
        {item}
      </option>
    );
  });

这篇关于使用ReactContext API过滤时丢失下拉选择选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆