gabnash
gabnash

Reputation: 79

How can parent component reset many children in React

I am writing an application that consists of a large grid of squares. Each square (or cell) maintains its own state. Clicking on an individual cell changes its colour (the Cell uses useState())

I want to have a single reset button that will set all the cells back to their initial state i.e. coloured white.

I can't work out how to get this single button to change the state of all the cells. The number of cells can vary (depending on the layout size selected) be between 121 and 529 of them.

Any advice greatfully accepted!

Upvotes: 2

Views: 1660

Answers (2)

Taghi Khavari
Taghi Khavari

Reputation: 6582

you can use a context and wrap all your cells in context.provider and then in your cells useEffect hook listen for the result of context if it changed you can change the state of each cell to its initial something like this:


//in resetContext.js

const ResetContext = React.createContext();

const useResetContext = () => React.useContext(resetContext);

//in resetContextProvider.js

const ResetContextProvider = () => {
  const [reset, setReset] = React.useState(false);
  const providerValue = {reset, setReset}

  return (
    <ResetContext.Provider value={providerValue}>
      //put your Cells in here
    </ResetContext.Provider>
  )
}

// in Cells

const initialValue = 'something';

const Cell = () => {
  const [cellState, setCellState] = React.useState(initialValue)
  const resetObj = useResetContext();

  React.useEffect(() => {
    if(reset){
      setCellState(initialValue)
    }
  }, [resetObj])

  return <div /> // or whatever your components are
}

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281626

The simplest solution is to actually change the key of the common parent of the grid element that forces all the children to remount and this resetting all their states

Sample demo

class Child extends React.Component {
   state = {
      counter: 0
   }
   render() {
    return (
      <div>{this.state.counter}<button onClick={() => this.setState(prev => ({counter: prev.counter+1}))}>Increment</button></div>
    )
   }
}
class App extends React.Component{
 state = {
  elemKey: 0,
 }
 
 render() {
  return (
   <React.Fragment>
    <div key={this.state.elemKey}>
      {[...Array.from(new Array(10))].map((item, index) => {
         return <Child key={index} />
      })}
    </div>
    <button onClick={() => {this.setState(prev => ({elemKey: (prev.elemKey + 1)%2}))}}>Reset</button>
   </React.Fragment>
  )
 }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"/>

Upvotes: 5

Related Questions