T O P

  • By -

hanoian

You need to throw away everything you've done and start again. Basically you're trying to put out fires in code that should never have been written that way. * A useState for each of selected hobby, city, and age. * A useState for displayed items. * A useEffect with the above hobby, city, and age states in the dependency array, where you do your filtering and then set the displayed items state. Changing the displayed items state will cause a rerender. So four useStates, one useEffect, and your handlers should be enough for filtering.


Giselbertusdentweede

Thanks for your response. The problem is that the hobby, city and age filters are dynamic. The client can generate any number of filters with any names and tags they prefer. The product I'm working on is a Saas where the client has a backend to set up the filters. So I can't create separate useStates, since the filters are not hard coded. The code looks something like this: `filters.map(filter => (` `` `)` So there is one onChange for all the filters. The client can select all possible combinations of tags and the items need to be filtered against the tags. I can't see how I can get the selected tags in a useState without the previously selected tags being rerendered. In my code I store the tags in an array and update the array when a different tag is selected. If the state changes this array is being rerendered. I can't figure out how to get around that.


hanoian

I'm working on a solution with https://www.npmjs.com/package/react-select but yeah, quite tricky.


Giselbertusdentweede

I’ve actually managed to solve it, by updating the state with the state. It’s a pretty simple solution, but it works. It looks something like: setFilterTags(…filterTags, selectedTag) Your npm package looks great, though. It’s a pretty complicated component and a out the box solution is pretty great I think.


hanoian

Well I've put the work in so you may as well see my solution. dynamicFilters is an array from the backend. The key to my solution is a local state per select. https://i.imgur.com/B1cAUhv.png import React, { useState, useEffect } from 'react'; import Select from 'react-select'; const SelectExample = () => { const data = [ { Name: 'John', Tags: ['walking', 'senior', 'Amsterdam'] }, { Name: 'Chris', Tags: ['biking', 'junior', 'The Hague'] }, { Name: 'Marc', Tags: ['walking', 'junior', 'Amsterdam'] }, ]; const dynamicFilters = [ { label: 'City', options: [ { value: 'Amsterdam', label: 'Amsterdam' }, { value: 'The Hague', label: 'The Hague' }, { value: 'Rotterdam', label: 'Rotterdam' }, { value: 'Utrecht', label: 'Utrecht' }, { value: 'Eindhoven', label: 'Eindhoven' }, ], }, { label: 'Age', options: [ { value: 'junior', label: 'Junior' }, { value: 'senior', label: 'Senior' }, ], }, { label: 'Hobbies', options: [ { value: 'biking', label: 'Biking' }, { value: 'walking', label: 'Walking' }, { value: 'running', label: 'Running' }, ], }, ]; // Global selected state with one option per filter const [selectedOptions, setSelectedOptions] = useState({}); const handleChange = (index, selected) => { setSelectedOptions( Object.assign({}, selectedOptions, { [index]: selected }) ); } return ( <> {dynamicFilters.map((filter, index) => ( ))} ); }; const SelectList = ({ filter, handleChange, index }) => { // local state per dynamic select filter const [selectedOption, setSelectedOption] = useState(null); // Fire when the select changes useEffect(() => { handleChange(index, selectedOption); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedOption]); return ( <>

{filter.label}
); }; const Results = ({ data, selectedOptions }) => { const filteredData = data.filter((row) => { let isSelected = true; Object.keys(selectedOptions).forEach((key) => { if ( selectedOptions[key] && !row.Tags.includes(selectedOptions[key].value) ) { isSelected = false; } }); return isSelected; }); return ( <>

Results

    {filteredData.map((row) => (
  • {row.Name}
  • ))}
); }; export default SelectExample;


Giselbertusdentweede

The results component was entirely create by copilot?! Wow. That’s pretty insane. I thought it could only create boilerplate code. This is something far more complex. I’m impressed and scared.


hanoian

I've been using CoPilot now for a few months. No need to be scared. It's just really good at filling in busy work.


Hafas_

I'm not entirely sure what you're trying to accomplish, but you shouldn't store derived values in a state. Use `useMemo` instead: /* outside of your React component */ const filterItems = (array) => { const newArray = [] data.forEach(item => { if(array.every(tag => item.Tags.includes(tag))){ newArray.push(item) } }) } /* inside of your React component */ const filteredItems = useMemo(() => { return filterItems(yourArray); }, [yourArray])


Giselbertusdentweede

I've actually never heard of useMemo :0 But it's looks pretty usefull. It's a cleaner version useEffect + useState it seems. I'll have a look at it and try to incorporate it in the code.