0
votes

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);
    }

})
1

1 Answers

1
votes

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.