ffxsam
ffxsam

Reputation: 27793

React and pre-binding functions for performance

I just read this highly enlightening article today:

https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f

The article uses the following example to show how to pre-bind functions to prevent components from needless re-rendering:

class App extends PureComponent {
  constructor(props) {
    super(props);
    this.update = this.update.bind(this);
  }
  update(e) {
    this.props.update(e.target.value);
  }
  render() {
    return <MyInput onChange={this.update} />;
  }
}

This makes sense, though I can't figure out how to pass an argument to the function without using bind or () => this.myFunc('some arg'). Example:

  <div>
    <TextField
      floatingLabelText="Email"
      required
      value={this.state.email}
      onChange={e => this.setState({email: e.target.value})}
    />
  </div>
  <div>
    <TextField
      type="password"
      floatingLabelText="Password"
      required
      value={this.state.password}
      onChange={e => this.setState({password: e.target.value})}
    />
  </div>

I'm not sure how to refactor this to not use binding. I've got this class method as a starting point:

_textChange(field, value) {
  this.setState({
    [field]: value,
  });
}

But I'm not sure how to pass arguments into it from the onChange prop and follow the suggestions laid out by the article above.

Additionally, I have code that I've refactored into this:

export default OrgList = (props) => {
  const orgs = props.orgs.map((org) => {
    const addEditOrg = props.onAddEditOrg.bind(null, org, 'edit');
    const deleteOrg = props.onDeleteOrg.bind(null, org);

    return <TableRow key={org._id}>
      <TableRowColumn>{org.name}</TableRowColumn>
      <TableRowColumn>
        <IconButton onTouchTap={addEditOrg}>
          <ModeEdit />
        </IconButton>
        [...]

But I'm not sure if those pre-bound functions are in the right place. Do they need to be totally outside the component?

Upvotes: 3

Views: 830

Answers (2)

Dmitri
Dmitri

Reputation: 668

I use name attribute for this. Example:

handleChange(e) {
  this.setState({[e.target.name]: e.target.value})
}

<TextField
  name="email"
  onChange={this.handleChange}
/>

<TextField
  name="password"
  onChange={this.handleChange}
/>

Upvotes: 4

Andreyco
Andreyco

Reputation: 22872

Unfortunately, you have to create separate methods which set email/password.

linkState is noop here, since it always returns different object. Same apply to higher order function (returning anonymous function as handler).

I would end up with this code. Event handlers are same, no unnecessary rendering is triggered this way.

setEmail(e) {
  this.setState({email: e.target.value})
}

setPassword(e) {
  this.setState({password: e.target.value})
}

<TextField
  onChange={this.setEmail}
/>

<TextField
  onChange={this.setPassword}
/>

Upvotes: 1

Related Questions