botbot
botbot

Reputation: 7359

React Native can't access this.props outside of render() method

I am trying to access this.props in the clicked() method, but they are undefined. How can I access this.props through the methods in the ListItemExample class?

My goal is to maintain the id into the show view that shows the detail view for a clicked ListItemExample.

export default class Example extends Component {

  constructor() {
    super();
    let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});

    this.state =  {
      dataSource: ds,
      isLoading: true
    };
  }

  componentDidMount() {
    this.fetchData()
  }

  fetchData() {

    Api.getPosts().then((resp) => {
      console.log(resp);
      this.setState({
        dataSource: this.state.dataSource.cloneWithRows(resp.posts),
        isLoading: false
      })
    });

  }

  render() {
    return (
      <View style={styles.container}>

          <ListView
              dataSource={this.state.dataSource}
              renderRow={this.renderRow.bind(this)}
              style={styles.postList}
              />

      </View>
    );
  }

  renderRow(post) {
    return (
        <PostListItem
          id={post.id}
          coverImage={post.cover_image}
          title={post.title}
          lockedStatus={post.status}
          time={post.time} />
    );
  }

}



export default class ListItemExample extends Component {

  constructor() {
    super();
  }

  render() {
    return (
      <TouchableHighlight onPress={this.clicked} >
        <View style={styles.postItem}>


        </View>
      </TouchableHighlight>
    );
  }

  clicked() {
    console.log("clicked props");
    console.log(this.props);
    Actions.openPost();
  }

}

Upvotes: 20

Views: 15775

Answers (6)

Desarrollalab
Desarrollalab

Reputation: 397

In then compnent that you're trying enter to another view you must send the object navigation by you use this in the onPress of component imported

example

Implementing component in a view

<CardComponent title="bla bla" navigation={this.props.navigation} />

Component template

`<View>
       <Button  title={this.props.title} onPress={()=> 
       this.props.navigation.navigate("anotherAwesomeView")}/>
</View>`

This problem is because the component that you're trying implement is not defined on stackNavigation, and by this the methot navigation is not avalible for you, and passing this object navigator by params you'll can access to it

Upvotes: 0

fandro
fandro

Reputation: 4903

You need to do onPress={this.clicked.bind(this)}

Upvotes: 27

Ooki Koi
Ooki Koi

Reputation: 330

You can use arrow functions for your handlers and bind to the lexical scope automagically. ... or go down the traditional .bind(this) at invocation time or in your constructor. But note, as I think one answer uses this approach: you must change your babel settings and ensure you have "optional": ["es7.classProperties"] for arrow functions in classes to work properly.

Upvotes: 0

Aditya Kresna Permana
Aditya Kresna Permana

Reputation: 12099

Add bind(this) to binding your method into current component, like

yourMethod(){
    console.log(this.props)
}    

<SomeComponent onClick={this.yourMethod.bind(this)} />

Upvotes: 7

Oleg Novosad
Oleg Novosad

Reputation: 2421

I had same issue when using FBSDK with React Native. And @fandro answer almost did explain a lot.

I had this:

render() {
        const infoRequest = new GraphRequest(
            '/me',
            null,
            this.responseInfoCallback,
        );

        return (
            <View>
                <LoginButton
                    readPermissions={["email"]}
                    onLoginFinished={
                        (error, result) => {
                            if (error) {
                                console.log("Login failed with error: " + result.error);
                            } else if (result.isCancelled) {
                                console.log("Login was cancelled");
                            } else {
                                new GraphRequestManager().addRequest(infoRequest).start(1000);
                                console.log("Login was successful with permissions: " + result.grantedPermissions)
                            }
                        }
                    }
                    onLogoutFinished={() => alert("User logged out")}/>
            </View>
        );
    }

responseInfoCallback(error, result) {
        if (error) {
            alert('Error fetching data: ' + error.toString());
        } else {
            alert('Success fetching data: ' + result.toString());
            this.props.onLoginSuccess();
        }
    }

And call of this.props.onLoginSuccess() caused issue "undefined is not an object evaluating this.props.onLoginSuccess()". So when I changed the code in const infoRequest = new GraphRequest(...) to include .bind(this):

const infoRequest = new GraphRequest(
        '/me',
        null,
        this.responseInfoCallback.bind(this),
    );

It worked. Hope this helps.

Upvotes: 0

Aditya Singh
Aditya Singh

Reputation: 16660

With the shift of React from createClass to ES6 classes we need to handle the correct value of this to our methods on our own, as mentioned here: http://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes Change your code to have the method bounded to correct value of this in constructor using this.clicked = this.clicked.bind(this) in your constructor

The no autobinding was a deliberate step from React guys for ES6 classes. Autobinding to correct context was provided with React.createClass. Details of this can be found here: https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding

So based on this you could also change your clicked method as:

export default class ListItemExample extends Component {

 constructor(props) {
   super(props);
 }

 render() {
   return (
    <TouchableHighlight onPress={this.clicked} >
      <View style={styles.postItem}>


      </View>
    </TouchableHighlight>
  );
 }

 clicked = () => {
   console.log("clicked props");
   console.log(this.props);
   Actions.openPost();
 }

}

Upvotes: 12

Related Questions