Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting and Filtering React - Context

Tags:

reactjs

I did a little bit of research but I found old examples with usually Redux or with one main component and cannot figure out the logic.

I can get data from an API but I do need to search, sort, filter, etc on that data (even at the same time). I know that I should not mutate the state directly, so in this case, I will have a couple of different state sets such as filteredData, sortedData, etc. However, which state am I going to pass to the Player component? How will sorting functionality will work on filtered data? I am extremely confused.

I would like to put my state and state-related logic in a Context but if this seems problematic or wrong, then I can try your approach.

Context

const ContextProvider = ({ children }) => {

  const [data, setData] = useState([]);
  const [filteredData, setFilteredData] = useState([]);
  const [sortedData, setSortedData] = useState([]);

  useEffect(() => {
    fetch('URL HERE')
      .then(data => data.json())
      .then(data=> setData(data));
  }, []);

  const handleSearch = e => {
    let value = e.target.value;
    const filteredData = data.filter(player=>
        player.name.includes(value)
    );
    setFilteredData(filteredData);
  };

  const handleSort = e => {
    let value = e.target.value;
    // I am trying to sort FILTERED DATA?
    const sortedData = filteredData.sort((a, b) => {
      if (a[value] < b[value]) {
        return 1;
      } else {
        return -1;
      }
    });
    setSortedData(sortedData);
  };

  return (
    <Context.Provider
      value={{ data, handleSearch, handleSort, filteredData, sortedData}}
    >
      {children}
    </Context.Provider>
  );
};

Search

const Search = () => {

  const { handleSearch, handleSort } = useContext(Context);
  return (
    <div className='row'>
      <Input
        type='search'
        name='search'
        onChange={handleSearch}
      ></Input>
      <Input
        type='select'
        name='select'
        onChange={handleSort}
      >
        <option value='name'>Name</option>
        <option value='team'>Team</option>
      </Input>
    </div>
  );
};

Player

const Player = () => {
  const {data, filteredData, sortedData} = useContext(Context);
  return (
      <ul>
        //{data or filteredData or sortedData will be mapped?}
        <li>// not sure what to do</li>
      </ul>
  );
};

I really appreciate code examples with some explanation.

like image 488
TToprak1 Avatar asked May 06 '26 14:05

TToprak1


1 Answers

There are many ways you can do this.

My suggestion would be:-

  1. Set const [filteredData, setFilteredData] = useState(data) (this will not work). So do useEffect() to update filteredData in Player then:-
useEffect(() => {
  setFilteredData(data)
}, [])
  1. On every request (inputs) made by user will be updated by setFilteredData()
  • if user do nothing with the inputs, then return filteredData which contain dafault data
  • if user do search input, then do filtering search on filteredData (using setFilteredData())
  • if user do sort input, then do sorting on filteredData (using setFilteredData())
  • if user do both search and sort inputs, then do both action on filteredData (using setFilteredData())
  1. in Player, you can just return filteredData

Context

const ContextProvider = ({ children }) => {

  const [data, setData] = useState([]);
  const [filteredData, setFilteredData] = useState([]);
  const [searchKey, setSearchKey] = useState('');
  const [sortKey, setSortKey] = useState([]);

  useEffect(() => {
    fetch('URL HERE')
      .then(data => data.json())
      .then(data=> setData(data));
  }, []);

  const handleSearch = () => {
    const filteredData = filteredData.filter(player=>
        player.name.includes(searchKey)
    );
    setFilteredData(filteredData);
  };

  const handleSort = () => {
    const sortedData = filteredData.sort((a, b) => {
      if (a[sortKey] < b[sortKey]) {
        return 1;
      } else {
        return -1;
      }
    });
    setFilteredData(sortedData);
  };

  return (
    <Context.Provider
      value={{
        data, filteredData, searchKey, sortKey,
        setFilteredData, setSearchKey, setSortKey,
        handleSearch, 
        handleSort, 
      }}
    >
      {children}
    </Context.Provider>
  );
};

Search

const Search = () => {

  const {
    searchKey, setSearchKey,
    sortKey, setSortKey
  } = useContext(Context);
  
  return (
    <div className='row'>
      <Input
        type='search'
        name='search'
        value={searchKey}
        onChange={e => setSearchKey(e.target.value)}
      ></Input>
      <Input
        type='select'
        name='select'
        value={sortKey}
        onChange={e => setSortKey(e.target.value)}
      >
        <option value='name'>Name</option>
        <option value='team'>Team</option>
      </Input>
    </div>
  );
};

Player

const Player = () => {
  const {
    data,
    filteredData, setFilteredData,
    searchKey, sortKey.
    handleSearch, handleSort
  } = useContext(Context);
 
  // set filteredData
  useEffect(() => {
    setFIlteredData(data)
  }, []) // should run once on mounted

  // do search
  // should be dependent on search input state (so you need a state to hold value need for searching)
  useEffect(() => {
    handleSearch()
  }, [searchKey]) // will only fired/run if searchState changes

  // do sorting
  // should be dependent on sorting input state (so you need a state to hold value need for sorting)
  useEffect(() => {
    handleSort()
  }, [sortKey]) // will only fired/run if sortingState changes

  return (
      <ul>
        {filteredData.map(data => (
          {/* display data info */}
        ))}
      </ul>
  );
};
like image 158
lala Avatar answered May 09 '26 06:05

lala



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!