loading...

Fast & easy... React states management in one function

Fabio Russo on June 23, 2018

Don't repeat the code... In React, like anywhere else in your code, you must never repeat yourself unless it is strictly necessary (al... [Read Full]
markdown guide
 

Yeah, curried functions are perfect for this. The arrow syntax lends itself to this.

valueChange = (key) => {
  return function (e) {
    var obj= {};
    state[key] = e.target.value; //<-- this is a bug btw.
    this.setState(obj);
  }.bind(this);
}

becomes

valueChange = key => e => this.setState(oldState => ({
  ...oldState,
  [key]: e.target.value
}))
 

Or just valueChange = key => e => this.setState({[key]: e.target.value})

 
 
 

using curried function is a good idea! it's very useful for handling multiple similar state changes.
another approach, if you're dealing with form elements like inputs etc. would be to use name attribute, something like this:

state = {
  firstName: '',
  message: '',
}

handleValueChange = e => {
  this.setState(() => ({ [e.target.name]: e.target.value }));
}

render() {
  return (
    <form>
      <input
        type="text"
        name="firstName"
        value={this.state.firstName}
        onChange={this.handleValueChange}
      />
      <input
        type="text"
        name="message"
        value={this.state.message}
        onChange={this.handleValueChange}
       />
    </form>
  )
}

but of course it works only with certain html elements (<input>, <select>, <textarea> among them) and IIRC specification says name should be lowercase, although I don't think I've run into any problems with camelCase name so far.

 

I like this, how about leveraging a data- attribute instead of name?

 

You're creating a new function for every input you manage for every render pass. This is an anti pattern especially on big state trees. Especially because it will cause re-renders of child components unnecessarily (as the onChange prop for each element changes every render pass. You may want to cache the created functions, or take a different approach

 
 

I think so, what specifically did I overlook? Supplying a better alternative?

There’s a warning about rerendering... and me asking for suggestions ✌🏻

Sorry if it’s not perfect, I’m here for learning too.

No worries, just wanted to chip in. Somehow dont see a note about rerender, I'm on mobile, perhaps some caching going on.

I like the alternative via name prop for input elements, or a custom data prop, as I wrote in the other comment thread.

Alternatively, I would still create a function property per onChange handler, but create and use a reusable function to limit the repetitiveness to the bare minimum.

You can create a curried function and then memoize it. 😉 It should work! Have a look at Lodash's curry and memoize functions.

 

You can try this alternative instead that doesn't require you to add any instance method (methods declared using arrow fns).

import React from "react";

// you can move this fn to an independent module and import it here
const setState = (component, updateState) => params =>
  component.setState(updateState(params));

const setName = event => prevState => ({
  ...prevState,
  name: e.target.value
}); 

export default class App extends Component {
  state = {
    name: ""
  };

  render() {
    return (
      <div>
        <input
          placeholder="insert your name" value={this.state.name} 
          onChange= {setState(this, setName)} />
      </div>
    );
  }
};
 

The approach demonstrated in this post to manage form data is known as controlled components, which is traditional "reactish" way to handle input value changes. Since the post is intended for beginners, maybe you could complement it adding a note to mention this for those who'd like to read further on the subject. 🙂

More details can be found here: reactjs.org/docs/uncontrolled-comp...

 

In the valueChange function where did you find the state variable. May be it should be obj variable ?

 

In the second example?

The state is the obj variable.
You can see I’m creating an obj and using key-value pairs in It.
Then I’m passing the object to setState().

 

you defining obj, but then you use state. in non-strict mode this leads to the creation of a global variable, in strict mode this leads to an error.

After that you use obj again, so the new value saved in state in state isn't even used.

code of conduct - report abuse