javascripting
javascripting

Reputation: 1153

React - how to keep state unchanged even when component re renders?

Every time I iterate through the products array, I render the Items component. There is a button ("show Gallery") that triggers the render of the products component and showing products. When I render Items component I also always render the checkbox. Is there a way that I can isolate the checkbox component to preserve the checked state? Because now whenever the "show Gallery" button is clicked, I re render everything and my checkbox is unchecked again. I hope I was clear enough with my question. Thanks

const otherComponent = () => { 
 //set showGallery globally to true or false
}

const Gallery = () => {
  const products =[...]
  return (
    {showGallery && 
      <Child products={products}/>
    }
  )
}

const Child = ({products}) => {
  return (
    <div>
      {products.map((product)=> {
        return <Item name={product.name}/>
      })}
    </div>
  )
}

const Item = ({name}) => {
  const handleFilter = () => {
    //call function that filters products and other logic
  }
  return (
    //...code
    <h1>{name}</h1>
      <Checkbox handleFilter={handleFilter}/>
    //...code
  )
}

const Checkbox = ({handleFilter}) => {
  const [checked, setChecked] = React.useState(false)
  const checkStyle = checked ? "show" : "hide"
  const handleCheckbox = () => {
    setChecked(!checked)
    handleFilter(checked)
  }
  return (
    <button
    className="checkbox"
    onClick={() => handleCheckbox()}
  >
    <Checkmark className={`${checkStyle} checkmark`} />
  </button>
  )
}

Upvotes: 0

Views: 808

Answers (1)

Julius Guevarra
Julius Guevarra

Reputation: 898

You could create a CheckboxProvider which stores the checked state of each Checkbox

import React from "react";

export const CheckboxContext = React.createContext({});
const CheckboxProvider = ({ children }) => {
  const [checkboxState, setCheckboxState] = React.useState({});

  const saveCheckboxState = (key, val) => {
    setCheckboxState({
      ...checkboxState,
      [key]: val
    });
  };

  React.useEffect(() => {
    console.log(checkboxState);
  }, [checkboxState]);

  return (
    <CheckboxContext.Provider
      value={{
        state: checkboxState,
        saveCheckboxState
      }}
    >
      {children}
    </CheckboxContext.Provider>
  );
};

export default CheckboxProvider;

Then wrap the contents of return of Gallery with the CheckboxProvider

Gallery.js

const Gallery = () => {
  // ...
  return (
    <CheckboxProvider>
      <button onClick={() => setShowGallery(!showGallery)}>
          {showGallery ? "Hide Gallery" : "Show Gallery"}
        </button>
        {showGallery && <Child products={products} />}
    </CheckboxProvider>
  )
}

And consume the state of checkbox like so:

Checkbox.js

const Checkbox = (id, handleFilter) => {
  const { state, saveCheckboxState } = React.useContext(CheckboxContext);
  
  // ...
}

See the CODESANDBOX for the demo.

Upvotes: 1

Related Questions