Sam Parmenter
Sam Parmenter

Reputation: 1841

React Native passing functions with arguments as props

From what I have read its best to try and structure react apps with as many components as "dumb" renderers. You have your containers which fetch the data and pass it down to the components as props.

That works nicely until you want to pass functions down the chain that require arguments other than events.

class MyClass extends Component {


  _onItemPress (myId) {
    // do something using myId
  }

  render () {

    return <MyComponent myID={10} onPress={(myId) => this._onItemPress(myId)} />

  }

}

If I simply pass that as my onPress handler to MyComponent it won't return myId when called. To get around this I end up doing something like this.

export default ({myId, onPress) => {
  const pressProxy = () => {
    onPress(myId)
  }

  return (
    <TouchableHighlight onPress={pressProxy}>
      <Text>Click me to trigger function</Text>
    </TouchableHighlight>
  )
}

Am I doing this completely incorrectly? I would like to be able to have a simple component that I can re-use for list items where its sole function is to take a title, onpress function and return a list item to be used in ListViews renderRow function. Many of the onPress functions will require variables to be used in the onPress however.

Is there a better way?

Upvotes: 11

Views: 30959

Answers (2)

blaz
blaz

Reputation: 4068

You did it correctly.

MyComponent is as "dumb" as it should be: it does not care about the source of its props, it acts independently from higher level of logic of the app and it can be reused somewhere else in the app.

Some improvements you can work on:

  1. MyComponent does not need myId itself. Exclude it from the component and let parental component deals with related logics to id

  2. Provide a safe check for props onPress. If you want to reuse MyComponent somewhere, it is better to check for existence of onPress property before calling it, or provide a default value for onPress in case developer adds in unwanted props types.

Example of MyComponent

class MyComponent extends Component {
  handlePress = (e) => {
    if (typeof this.props.onPress === 'function') {
      this.props.onPress()
    }
  }

  render() {
    return (
      <TouchableHighlight onPress={this.handlePress}>
        <Text>Click me to trigger function</Text>
      </TouchableHighlight>
    )
  }
}

and to call MyComponent in MyClass:

class MyClass extends Component {
  _onItemPress(myId) {

  }

  render () {
    return <MyComponent onPress={() => this._onItemPress(10)} />

  }

}

Upvotes: 0

Incinerator
Incinerator

Reputation: 2807

The proper syntax would be something like this:

render () {
    let myId = 10;
    return <MyComponent myID={myId} onPress={() => this._onItemPress(myId)} />
}

Also, if you plan to use this inside _onItemPress (for example to call other methods in MyClass), you need to bind the scope like this:

render () {
    let myId = 10;
    return <MyComponent 
        myID={myId} 
        onPress={() => this._onItemPress(myId).bind(this)} />
}

...or you can bind it already in the constructor if you prefer:

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

Upvotes: 2

Related Questions