1

For my four in a row game I create an Array of components. I need to call a method of one specific component from the parent component.

Here are the two methods that are building the Field. At renderRow I put the ref into an Array which is defined in the constructor.

renderRow(row){
  var Buttons = new Array(this.props.w)
    for (var i = 0; i < this.props.w; i++) {
    thisButton=<FieldButton ref={(r) => { this.refField['row'+ row +'col'+ i] = r; }} handler={this.actionFunction} key={'row'+ row +'col'+ i}></FieldButton>
    Buttons.push(thisButton)
  }
  return Buttons
}

renderField(){
  var Field = new Array(this.props.h);
  for (var i = 0; i < this.props.h; i++) {
    var row = this.renderRow(i);
    Field.push(<View key={i} style={styles.fieldWrap}>{row}</View>);
  }
  this.field = Field;
}

The actionFunction should simply print the current ref.

actionFunction(pos) {
  console.log(this.refField['row'+ pos.row +'col'+ pos.col])
}

The problem: The output is undefined.

Edit: If I console.log the reField variable this is the output: enter image description here

5
  • 1
    line 4: thisButton should be declared like var thisButton or const thisButton. This could just be a typo. Commented Dec 9, 2017 at 23:56
  • Did not change anything. Commented Dec 10, 2017 at 0:04
  • Did you initialize the object refField like this.refField = {} Commented Dec 10, 2017 at 14:08
  • I did like this.refField = [] but also tried with {} Commented Dec 10, 2017 at 15:08
  • Ok then have you printed out your pos variable in your actionFunction to make sure it is correct? Commented Dec 11, 2017 at 17:18

2 Answers 2

1

The solution is that I had to use let instead of var to initialise the variables in the for loop. Working code:

renderRow(row){
  var Buttons = new Array(this.props.w)
  for (let i = 0; i < this.props.w; i++) {
    let thisButton=<FieldButton ref={(r) => { this.refField['row'+ row +'col'+ i] = r; }} handler={this.actionFunction} key={'row'+ row +'col'+ i}></FieldButton>
    Buttons.push(thisButton)
  }
  return Buttons
}

renderField(){
  var Field = new Array(this.props.h);
  for (let i = 0; i < this.props.h; i++) {
    let row = this.renderRow(i);
    Field.push(<View key={i} style={styles.fieldWrap}>{row}</View>);
  }
  this.field = Field;
}
Sign up to request clarification or add additional context in comments.

Comments

0

React actually has a special property just for this called refs!

https://reactjs.org/docs/refs-and-the-dom.html

You can actually just set a name for the reference to the object and then access that object anywhere in your class using this.refs.referenceName. Do note that when you set the reference on the object the property name is 'ref' (singular) and when you want to access it you use 'this.refs' (plural). For instance:

renderRow(row){
  var Buttons = new Array(this.props.w)
  for (var i = 0; i < this.props.w; i++) {
    const thisButton=<FieldButton ref={'row' + row + 'col' + i} handler={this.actionFunction} key={'row'+ row +'col'+ i}></FieldButton>
    Buttons.push(thisButton)
  }
return Buttons
}

Now, if you need to get that FieldButton from your actionFunction:

actionFunction(pos) {
  console.log(this.refs['row'+ pos.row +'col'+ pos.col])
}

Note: also make sure your function is being bound to the class instance.

2 Comments

I did try that before and I got this: Element ref was specified as a string (add) but no owner was set. You may have multiple copies of React loaded. so I decided to use the other way.
Well then your problem is you are loading multiple copies of React. Once you fix that issue you can work through this one. Could be one of your dependencies is loading a duplicate copy of React? You need to fix this issue though, as everything could be working it's just that one copy of react has the correct data and the other copy(copies) don't which is where actionFunction is getting called. Who knows what happens if you multiple copies of React it could cause a lot of mystery bugs like this though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.