franklinsing
franklinsing

Reputation: 33

How to access variables inside render in ReactJS from another class (EDIT: another js page) (ES6 and Node is being used)

I want to disable onClick while the game's AI is making a move (startThinking function) so that players don't randomly click on any part of the game and mess it up.

Here is my code for the class from which I want to access the variables onclick and cursor (relevant bits surrounded by ** **):

class Grid extends React.Component{
        constructor(props){
          super(props);
          var pos = props.pos;
          this.xPos = 2+(pos%9)*66+"px";
          this.yPos = 2+(Math.floor(pos/9))*66+"px";
          this.borderTop = "none";
          this.borderLeft = "none";
          this.borderRight = "none";
          this.borderBottom = "none";
          if(pos%3==0){
            this.borderLeft = "solid";
          }
          if(pos%9==8){
            this.borderRight = "solid";
          }
          if(pos>71){
            this.borderBottom = "solid";
          }
          if((pos%27)<9){
            this.borderTop = "solid";
          }
      }

        render(){
          var pos = this.props.pos;
          var icon = this.props.icon;
          var backgroundColor = (icon==="none")?((!this.props.legal)?((pos%2)?"white":"#f2f2f2"):((pos%2)?"rgb(177, 251, 169)":"rgb(157, 228, 150)")):((icon==="x")?"rgb(243, 125, 125)":"#6f83f3");
          var choice = "";
          var **onclick** = (this.props.legal)?this.props.onclick:(()=>{});
          var **cursor** = (this.props.legal)?"pointer":"default";
          if(icon !== "none"){
              choice = (<div className='icon'>{icon}</div>);
          }
          return(<div onClick={onclick} style={{cursor:cursor,backgroundColor:backgroundColor,top:this.yPos,left:this.xPos,borderLeft:this.borderLeft,borderRight:this.borderRight,borderTop:this.borderTop,borderBottom:this.borderBottom}} className='grid' >{choice}</div>);
        }
      }

Here is the class from which I want to access the variables onclick and cursor from and change them to the default value (i.e. not active) before the gameAI starts thinking and then I want to revert them back to original after the gameAI finishes thinking and has made a move. Relevant bits surrounded by ** **

class Board extends React.Component {
        constructor(props){
          super(props);
          this.state = {
            model: curGame
          }
          setSimBoard(this);
        }

        render() {
          var model = this.state.model;
          var i = -1;

          var comps = model.grid.map((sq)=>{
            i++;
            var n = "block_"+i;
            var leg = model.legals.indexOf(i)>-1;
            return <Grid id={n} key={n} pos={i} icon={sq.icon} legal={leg} onclick={
              ((i)=>{
                  **  return ()=>{
     // the comments are what i tried, didn't work    Grid.onclick = (()=>{});
                    //  Grid.cursor = "default";
                      startThinking(i);
                      model.makeMove(i);
                   //   Grid.onclick = (this.props.legal)?this.props.onclick:(()=>{});
                    //  Grid.cursor = (this.props.legal)?"pointer":"default";
                      this.setState({model:model});

                    }
                  })(i) **
            }/>;
          });

          return (
            <div>
              <div>{comps}</div>
              <BoardStatus model={model}/>
              <WinCover model={model}/>
            </div>
          );
        }
      }

Finally, here's the startThinking function, which is in another js file. Comments are what I tried. ai belongs to another file, which is the gameAI while it's doing the computation for making a move.

function startThinking(i){
  //document.getElementById('id').style.pointerEvents = 'none'; 
  console.log("thinking..");
  ai.postMessage({game:Object.assign({"ai":true}, curGame) ,move:i});
//  document.getElementById('id').style.pointerEvents = 'auto';  
}

I'd really appreciate some help on this! Thank you very much!

EDIT: So, Pranesh Ravi told me how to access variables from a class in another class. However, since that didn't solve my issue, I'd like to know how to access the onclick and cursor variables from another file, ai.js, the relevant parts of which are shown below and the super relevant parts are surrounded by ** **. Comments are what I tried to disable click while gameAI is working, which gave me a reference error saying Board is not defined which makes sense.

    var thinkTime = 2000;
    var think = false;
    var maxDepth = 6;
    onmessage = function(msg){
   ** //  Board.onclick = (()=>{});
    //  Board.cursor = "default"  **
      var game = msg.data.game;
      var playerMove = msg.data.move;
      think = true;
      var search = new SearchTree(game,playerMove,0);
      var bestMove = search.traverse(maxDepth,true);
      console.log(bestMove);
      postMessage(bestMove.move);
  **   // Board.onclick = (this.props.legal)?this.props.onclick:(()=>{});
     // Board.cursor = (this.props.legal)?"pointer":"default";  **
}

Upvotes: 1

Views: 3886

Answers (2)

Pranesh Ravi
Pranesh Ravi

Reputation: 19113

In your project, Board can extend from Grid instead of React.Component. And call super inside the constructor of Board. super will run the constructor of its parent class. So, all the this inside Grid will be available in Board now. Added a simple example to demonstrate this.

Hope this helps!

class Grid extends React.Component{
  constructor(props){
    super(props)
    this.onClick = 'This is a onclick variable'
    this.cursor = 'This is cursor'
  }
  render(){
    return <h1>Render from Component Grid</h1>
  }
}

class Board extends Grid{ //extending Grid
  constructor(props){
    super(props) //calling super to run the constructor of Grid
  }
  
  render(){
    console.log(this.onClick) //Accessing onClick from Grid
    console.log(this.cursor) //Accessing cursor from Grid
    return <h1>Render from Component Board</h1>
  }
}

ReactDOM.render(
  <div>
    <Grid/>
    <Board/>
  </div>
  , document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Upvotes: 0

Gaston Sanchez
Gaston Sanchez

Reputation: 1211

This a problem a library like Redux solves.

You have a central repository with the info of the state of your game. I ca give you two ways to solve it.

Option 1. Get a ref of the Grid component and call a function that returns the info that you need.

Option 2. Since it's bad practice to get refs of your components, a more pure way is to pass a function to your child component when it's rendered. Which is used to register a function that fetchs the info that you need. This is my recommended approach.

class Board extends Component {

  constructor(props) {
    super(props);
    this.registerStateFetcher = this.registerStateFetcher.bind(this);
  }

  registerStateFetcher(fetcher) {
    this.stateFetcher = fetcher;
  }

  render() {
    return <Grid registerStateFetcher={ this.registerStateFetcher } />
  }
}

class Grid extends Component {

  constructor(props) {
    super(props);
    props.registerStateFetcher(this.getGameState.bind(this));
  }

  getGameState() {
    // recollect info needed and return
    return {};
  }

}

Upvotes: 1

Related Questions