Reputation: 5021
I have a Grid with 3*3 squares.
When a click on a square , we change the background color to green.
So, I tried to put the all the states in the parent GridContainer.
state = {
gridCells: []
};
This will hold the indices that are clicked.
GridContainer
nests Grid
and Grid nests Square
.
render() {
return (
<div>
<Grid action={this.handler} />
<button>Reset Clicks</button>
</div>
);
}
Here is my current implementation.
Now how do I clear the background cells when I reset clicks and make the background back to white again?
function Square(props) {
const liClickHandler = event => {
event.target.classList.add("highlight");
props.clickAction();
};
return <li onClick={e => liClickHandler(e)} />;
}
function Grid(props) {
const gridHandler = index => {
props.action(index);
};
return (
<ul>
{Array.from(new Array(9)).map((item, index) => (
<Square key={index} clickAction={() => gridHandler(index)} />
))}
</ul>
);
}
class GridContainer extends React.Component {
state = {
gridCells: []
};
handler = index => {
let temp = [...this.state.gridCells];
temp.push(index + 1);
this.setState({
gridCells: temp
});
};
render() {
return (
<div>
<Grid action={this.handler} />
<button>Reset Clicks</button>
</div>
);
}
}
So when I click a Sqaure
, it calls a method clickAction
that calls handler
that updates the state and we have an array which indices were clicked in order.
How do I implement Reset clicks that updates the background of those Sqaures back to white
? How do I let know my child know.
Am I maintaining the state wrong?
Sandbox link : https://codesandbox.io/s/3-x-3-grids-s0b43?file=/src/index.js:640-1563
Upvotes: 1
Views: 477
Reputation: 1611
In react you should think the "react" way:
Here is corrected version of the demo:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function Square(props) {
return (
<li onClick={props.onClick} className={props.active ? "highlight" : ""} />
);
}
function Grid(props) {
let squares = [];
for (let i = 0; i < 9; i++) {
squares.push(
<Square
key={i}
onClick={() => props.onCellClick(i)}
active={props.cells[i]}
/>
);
}
return <ul>{squares}</ul>;
}
class GridContainer extends React.Component {
state = {
gridCells: []
};
onCellClick = index => {
this.setState(prevState => {
const newCells = [...prevState.gridCells];
newCells[index] = true;
return {
gridCells: newCells
};
});
};
render() {
return (
<div>
<Grid cells={this.state.gridCells} onCellClick={this.onCellClick} />
<button
onClick={() => {
let that = this; //we could bind the callback aswell
that.setState(() => ({ gridCells: [] }));
}}
>
Reset Clicks
</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<GridContainer />, rootElement);
Upvotes: 2
Reputation: 1032
I'd advise to rethink the way how your components are structured.
Each component should be independent unit with it's own logic and state (if needed of course). I'm saying if needed for state, cause ideally components should be stateless.
There are several problems with Square class:
Both these problems result in fact that you cannot reset presentation of your squares easily.
I've updated your sample: https://codesandbox.io/s/3-x-3-grids-uflhr?file=/src/index.js
It's still not ideal, but you can notice that gridCells is passed from top via props. And then each square gets own props param. This allows state to come through the flow and let squares rerender with updated class.
Upvotes: 2