Undefined is not an object evaluating this.state/this.props

前端 未结 4 890
心在旅途
心在旅途 2021-01-28 16:20

How do I bind a function outside of scope in React Native? I\'m getting the errors:

undefined is not an object evaluating this.state   

&

相关标签:
4条回答
  • 2021-01-28 16:25

    not sure if this is the problem, but I think is code is wrong, and may be potentially causing your issue.

    <View style={styles.cardContentLeft}>
      <TouchableHighlight style={styles.button}
       onPress={this._buttonPress().bind(this)}>
      <Text style={styles.restData}>View Video</Text>
      </TouchableHighlight>
    </View>
    

    specifically this line onPress={this._buttonPress().bind(this)}> you are invoking the function and binding it at the same time.

    The correct way to do this would be so

    onPress={this._buttonPress.bind(this)}>
    

    this way the function will be called only onPress.

    0 讨论(0)
  • 2021-01-28 16:26

    You are going in the right direction, but there is still a minor issue. You are passing a function to your map callback that has a different scope (this) than your component (because it is not an arrow function), so when you do bind(this), you are rebinding your callback to use the scope from map. I think this should work, it basically turns the callback that you pass to map into an arrow function. Also, since you bind your function in the constructor, you do not need to do it again:

      // The constructor logic remains the same
      // ....
      renderLoadingView() {
          return (
          <View style={[styles.cardContainer, styles.loading]}>
            <Text style={styles.restData}>
              Loading ...
            </Text>
          </View>
          )
        }
    
      _buttonPress = () =>  {
          this.props.navigator.push({
            id: 'Main'
          })
      }
    
      renderGPSDataFromServer =() => {
    
        const {loaded} = this.state;
        const {state} = this.state;
    
        return this.state.dataArr.map((data, i) => {
          return(
            <View style={[styles.cardContainer, styles.modularBorder, styles.basePadding]} key={i}>
    
              <View style={styles.cardContentLeft}>
                <TouchableHighlight style={styles.button}
                 onPress={this._buttonPress}>
                <Text style={styles.restData}>View Video</Text>
                </TouchableHighlight>
              </View>
    
              <View style={styles.cardContentRight}>
                <Text style={styles.restData}>{i}</Text>
                <View style={styles.gpsDataContainer}>
                  <Text style={styles.gpsData}>
                  {Number(data.lat).toFixed(2)}</Text>
                  <Text style={styles.gpsData}>{Number(data.long).toFixed(2)}</Text>
                </View>
                <Text  style={styles.gpsData}>
                {this.calcRow(55,55).bind(this)}
                </Text>
              </View>
    
            </View>
          );
        });
      }
    
      render = ()=> {
        if (!this.state.loaded) {
          return this.renderLoadingView();
        }
        return(
          <View>
            {this.renderGPSDataFromServer()}
          </View>
        )
      }};
    
    0 讨论(0)
  • 2021-01-28 16:34

    this.props are read-only

    React docs - component and props

    And therefore a component shouldn't try a to modify them let alone mutate them as you are doing here:

      _buttonPress = () =>  {
          this.props.navigator.push({
            id: 'Main'
          })
      }
    

    I'd suggest using state instead:

    _buttonPress = () =>  {
      this.setState = {
        ...this.state,
        navigator: {
          ...this.state.navigator,
          id: 'Main'
        }
      }
    }
    

    Regarding your binding issue:

    the .map method takes a 2nd argument that is used to set the value of this when the callback is invoked.

    In the context of your question, you just need to pass thisas the 2nd argument to you .map method to bind the components scope's this to it.

    0 讨论(0)
  • 2021-01-28 16:46

    This is happening because, the function inside the map method creates a different context. You can use arrow functions as the callback in the map method for lexical binding. That should solve the issue you are having.

    renderGPSDataFromServer =() => {
    
        const {loaded} = this.state;
        const {state} = this.state;
    
        return this.state.dataArr.map((data, i) => {
          return(
            <View style={[styles.cardContainer, styles.modularBorder, styles.basePadding]} key={i}>
    
              <View style={styles.cardContentLeft}>
                <TouchableHighlight style={styles.button}
                 onPress={this._buttonPress().bind(this)}>
                <Text style={styles.restData}>View Video</Text>
                </TouchableHighlight>
              </View>
    
              <View style={styles.cardContentRight}>
                <Text style={styles.restData}>{i}</Text>
                <View style={styles.gpsDataContainer}>
                  <Text style={styles.gpsData}>
                  {Number(data.lat).toFixed(2)}</Text>
                  <Text style={styles.gpsData}>{Number(data.long).toFixed(2)}</Text>
                </View>
                <Text  style={styles.gpsData}>
                {this.calcRow(55,55).bind(this)}
                </Text>
              </View>
    
            </View>
          );
        });
      }

    Also, once you've used arrow functions in the class function definition you don't need to bind them in constructor like:

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

    Also, once you have defined class functions as arrow functions, you don't need to use the arrow functions while calling them either:

    class Example extends React.Component {
      myfunc = () => {
        this.nextFunc()
      }
    
      nextFunc = () => {
        console.log('hello hello')
      }
    
      render() {
        // this will give you the desired result
        return (
          <TouchableOpacity onPress={this.myFunc} />
        )
        
        // you don't need to do this
        return (
          <TouchableOpacity onPress={() => this.myFunc()} />
        )
      }
    }

    0 讨论(0)
提交回复
热议问题