skip to Main Content

I have a parent component. Marketplace.js code-

export default function Marketplace() {

const [filters, setFilters] = useState(
        [
            {
                id: 'commodity',
                name: "Commodity",
                isSelected: false,
                type: "select",
                options: ['A', 'B', 'C', 'D', 'E'],
                value: null,
                availableFor: ['classifieds', 'auction']
            }
        ]
    );

return (
    <div>
        <FilterBar filters={filters} setFilters={setFilters} />
    </div>
)

The child component FilterBar.js code-

export default function FilterBar({ filters, setFilters }) {

    var copiedFilters = [...filters]
    const [newFilters, setNewFilters] = useState(copiedFilters);

    const onFilterChange = (e, item) => {
        if (e.target.value === '') {
            item.isSelected = false;
        } else {
            item.isSelected = true;
        }
        item.value = e.target.value;

        const updatedFilters = newFilters.map((filter) => {
            if (filter.id === item.id) {
                return {
                    ...filter,
                    isSelected: item.isSelected,
                    value: item.value,
                };
            } else {
                return filter;
            }
        });

        setNewFilters(updatedFilters);
    };

    ......

}

When setNewFilters() is used to set some new values, the ‘filters’ state passed from parent is also changed.

How can I fix this issue?

2

Answers


  1. One possible solution is to use JSON to get a deep copy:

    var copiedFilters = JSON.parse(JSON.stringify(filters));
    

    Changing copiedFilters now shouldn’t change filters or any of it’s values.

    Login or Signup to reply.
  2. You are mutating the state when you change the item’s value and isSelected props. Just do this instead:

    const onFilterChange = (e, item) => {
      const value = e.target.value;
      const isSelected = !e.target.value === '';
    
      setNewFilters((prevNewFilters) => {
        return prevNewFilters.map((filter) => {
          return filter.id === item.id ? {
            ...filter,
            value,
            isSelected,
          } : filter;
        });
      });
    };
    

    When you do:

    var copiedFilters = [...filters]
    

    You are creating a new array, but the items inside it are exactly the same, so you are still referencing the original state from the parent component.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search