Reputation: 65
I'm creating a Tic Tac Toe board in React. I'm trying to rest the board when a person clicks on the rest button that's in my app component. I'm trying to figure out whats the best approach dealing with this situation. I have been reading about uplifting, but if there is an easier way any suggestion would be helpful. here is my code
let data = {
"box":[
[ "", "", "" ],
[ "", "", "" ],
[ "", "", "" ]
],
"players": ['X','O']
}
class DataStore {
constructor(data, players) {
//store that data in the object
this.data = data;
this.players = players;
//empty array for our watchers
//watchers are objects that want to be informed about when the data changes
this.registeredWatchers = [];
}
//add a new watcher to the list
register(watcher) {
this.registeredWatchers.push(watcher);
}
setCrop(newDataState, row, col) {
//update data
this.data[row][col] = newDataState;
//inform all watching objects..
this.registeredWatchers.map((watcher) => {
watcher.dataUpdated();
})
}
}
class Dispatcher {
constructor() {
this.registeredHandlers = []; //D:
}
register(callback) {
this.registeredHandlers.push(callback);
}
dispatch(action) {
//call every method in our registered handlers array
//with this action as an input
this.registeredHandlers.map((handler) => {
//call that individual function in the array..
handler(action);
})
}
}
class BoxComponent extends React.Component {
render() {
return (
<div
className="box"
onClick={this.handleClick.bind(this)}>
<span>{this.props.type}</span>
</div>);
}
handleClick() {
//try a test dispatch
if(this.props.type.length > 0) {
return false;
} else {
boxDispatcher.dispatch({ type: "pick", row: this.props.rowNum, col: this.props.colNum});
}
}
}
class GridComponent extends React.Component {
constructor(props) {
//make sure this stays a react component
super(props);
this.state = {
turn: boxDataStore.players[0],
box: this.props.box
}
//ensure we're listening to the data store
boxDataStore.register(this);
}
dataUpdated() {
this.setState(prevState => ({
box: boxDataStore.data,
// turn: cropDataStore.players,
turn: prevState.turn === 'X'
? boxDataStore.players[1]
: boxDataStore.players[0]
}))
}
render() {
return(
<div>
{
//loop through all the rows...
this.state.box.map((row, rowNum) => {
//and write them out to the page..
return (<div className="row">
{
row.map((cropEntry, colNum) => {
return <BoxComponent type={cropEntry} rowNum={rowNum} colNum={colNum} turn={rowNum}/>
})
}
</div>);
})
}
</div>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<h1>Tic Tac Toe </h1>
<button onClick={this.resetBoard.bind(this)}>reset</button>
<GridComponent box={this.props.data}/>
</div>
);
}
resetBoard() {
}
}
//start of app
var boxDispatcher = new Dispatcher();
var boxDataStore = new DataStore(data.box, data.players);
boxDispatcher.register((action) => {
if(boxDataStore.registeredWatchers["0"].state.turn == "X") {
//actually waint to handle it
boxDataStore.setCrop('X', action.row, action.col);
} else {
boxDataStore.setCrop('O', action.row, action.col);
}
})
Upvotes: 0
Views: 261
Reputation: 2316
If you are reading about lifting state up you might have already read the page of the React official documentation that talks about it.
There should be a single “source of truth” for any data that changes in a React application. Usually, the state is first added to the component that needs it for rendering. Then, if other components also need it, you can lift it up to their closest common ancestor. Instead of trying to sync the state between different components, you should rely on the top-down data flow.
Basically, if you don't lift your state up, it's more difficult to maintain the single source of truth because you have to sync both states and it just doesn't feel right. I don't think there is "an easier way" to do that since it can cause you a lot of side effects.
Upvotes: 1