A person with a sweater working from a cozy room on a laptop
A person with a sweater working from a cozy room on a laptop
A person with a sweater working from a cozy room on a laptop
A person with a sweater working from a cozy room on a laptop
A person with a sweater working from a cozy room on a laptop

Why You Should Avoid Using Redux for Your Forms

Why You Should Avoid Using Redux for Your Forms

Why You Should Avoid Using Redux for Your Forms

Why You Should Avoid Using Redux for Your Forms

Javier Ponce

Javier Ponce

Javier Ponce

Dec 19, 2019

Dec 19, 2019

Dec 19, 2019

In recent years, we have learned to use Redux with simple applications like todo-lists or forms, but are these a good example? What if our application has grown considerably?

// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}
// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}

In this case, we are just reaching our single reducer when dispatching an action:

This may be “OK” for small apps but the latency will continue to increase as our app grows. Now, imagine that we have 50 reducers:

We will be hitting all the reducers on EVERY SINGLE KEYSTROKE.

As Dan Abramov says, forms are ephemeral and local. The redux state is intended to be global. Using a local state is fine, and if we need to share these values, we can lift up your state to the closest common ancestor.Handling the state locally

This is the same form using a local state:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      email: '',
      message: ''
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Name:
          <input
            name="name"
            type="text"
            value={this.state.name}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          E-mail:
          <input
            name="email"
            type="email"
            value={this.state.email}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          Message:
          <textarea
            name="message"
            type="text"
            value={this.state.comments}
            onChange={this.handleInputChange}
          />
        </label>
      </form>
    );
  }
}

With this approach we get the following benefits:

  1. No need to hit any reducer

  2. Better performance. Plus, this won’t be affected even if the app continues to grow (having more reducers)

But, what if we want to have more forms? Do we need copy-paste the handleInputChange function for each form? Or what if we need to run validations? Is there a way to avoid all this boilerplate code?

The answer to these questions is a nice alternative: Formik.

Formik does all this magic for us under the hood. I won’t cover how to use Formik in this post since it provides good documentation. However, I would like to mention that Formik + Yup will solve most of your problems.

Are you interested in looking at Formik in more depth? Let me know in the comments!

Conclusion

Using the local state on React is usually better. You should use Redux for complex state transitions, when you need to keep track of the changes or when it matters globally.

...

I created this repository which demonstrates the performance impact with lots of forms, feel free to take a look!: https://github.com/densitylabs/blog-reference-examples/tree/master/redux-in-forms

In recent years, we have learned to use Redux with simple applications like todo-lists or forms, but are these a good example? What if our application has grown considerably?

// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}
// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}

In this case, we are just reaching our single reducer when dispatching an action:

This may be “OK” for small apps but the latency will continue to increase as our app grows. Now, imagine that we have 50 reducers:

We will be hitting all the reducers on EVERY SINGLE KEYSTROKE.

As Dan Abramov says, forms are ephemeral and local. The redux state is intended to be global. Using a local state is fine, and if we need to share these values, we can lift up your state to the closest common ancestor.Handling the state locally

This is the same form using a local state:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      email: '',
      message: ''
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Name:
          <input
            name="name"
            type="text"
            value={this.state.name}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          E-mail:
          <input
            name="email"
            type="email"
            value={this.state.email}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          Message:
          <textarea
            name="message"
            type="text"
            value={this.state.comments}
            onChange={this.handleInputChange}
          />
        </label>
      </form>
    );
  }
}

With this approach we get the following benefits:

  1. No need to hit any reducer

  2. Better performance. Plus, this won’t be affected even if the app continues to grow (having more reducers)

But, what if we want to have more forms? Do we need copy-paste the handleInputChange function for each form? Or what if we need to run validations? Is there a way to avoid all this boilerplate code?

The answer to these questions is a nice alternative: Formik.

Formik does all this magic for us under the hood. I won’t cover how to use Formik in this post since it provides good documentation. However, I would like to mention that Formik + Yup will solve most of your problems.

Are you interested in looking at Formik in more depth? Let me know in the comments!

Conclusion

Using the local state on React is usually better. You should use Redux for complex state transitions, when you need to keep track of the changes or when it matters globally.

...

I created this repository which demonstrates the performance impact with lots of forms, feel free to take a look!: https://github.com/densitylabs/blog-reference-examples/tree/master/redux-in-forms

In recent years, we have learned to use Redux with simple applications like todo-lists or forms, but are these a good example? What if our application has grown considerably?

// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}
// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}

In this case, we are just reaching our single reducer when dispatching an action:

This may be “OK” for small apps but the latency will continue to increase as our app grows. Now, imagine that we have 50 reducers:

We will be hitting all the reducers on EVERY SINGLE KEYSTROKE.

As Dan Abramov says, forms are ephemeral and local. The redux state is intended to be global. Using a local state is fine, and if we need to share these values, we can lift up your state to the closest common ancestor.Handling the state locally

This is the same form using a local state:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      email: '',
      message: ''
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Name:
          <input
            name="name"
            type="text"
            value={this.state.name}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          E-mail:
          <input
            name="email"
            type="email"
            value={this.state.email}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          Message:
          <textarea
            name="message"
            type="text"
            value={this.state.comments}
            onChange={this.handleInputChange}
          />
        </label>
      </form>
    );
  }
}

With this approach we get the following benefits:

  1. No need to hit any reducer

  2. Better performance. Plus, this won’t be affected even if the app continues to grow (having more reducers)

But, what if we want to have more forms? Do we need copy-paste the handleInputChange function for each form? Or what if we need to run validations? Is there a way to avoid all this boilerplate code?

The answer to these questions is a nice alternative: Formik.

Formik does all this magic for us under the hood. I won’t cover how to use Formik in this post since it provides good documentation. However, I would like to mention that Formik + Yup will solve most of your problems.

Are you interested in looking at Formik in more depth? Let me know in the comments!

Conclusion

Using the local state on React is usually better. You should use Redux for complex state transitions, when you need to keep track of the changes or when it matters globally.

...

I created this repository which demonstrates the performance impact with lots of forms, feel free to take a look!: https://github.com/densitylabs/blog-reference-examples/tree/master/redux-in-forms

In recent years, we have learned to use Redux with simple applications like todo-lists or forms, but are these a good example? What if our application has grown considerably?

// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}
// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}

In this case, we are just reaching our single reducer when dispatching an action:

This may be “OK” for small apps but the latency will continue to increase as our app grows. Now, imagine that we have 50 reducers:

We will be hitting all the reducers on EVERY SINGLE KEYSTROKE.

As Dan Abramov says, forms are ephemeral and local. The redux state is intended to be global. Using a local state is fine, and if we need to share these values, we can lift up your state to the closest common ancestor.Handling the state locally

This is the same form using a local state:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      email: '',
      message: ''
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Name:
          <input
            name="name"
            type="text"
            value={this.state.name}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          E-mail:
          <input
            name="email"
            type="email"
            value={this.state.email}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          Message:
          <textarea
            name="message"
            type="text"
            value={this.state.comments}
            onChange={this.handleInputChange}
          />
        </label>
      </form>
    );
  }
}

With this approach we get the following benefits:

  1. No need to hit any reducer

  2. Better performance. Plus, this won’t be affected even if the app continues to grow (having more reducers)

But, what if we want to have more forms? Do we need copy-paste the handleInputChange function for each form? Or what if we need to run validations? Is there a way to avoid all this boilerplate code?

The answer to these questions is a nice alternative: Formik.

Formik does all this magic for us under the hood. I won’t cover how to use Formik in this post since it provides good documentation. However, I would like to mention that Formik + Yup will solve most of your problems.

Are you interested in looking at Formik in more depth? Let me know in the comments!

Conclusion

Using the local state on React is usually better. You should use Redux for complex state transitions, when you need to keep track of the changes or when it matters globally.

...

I created this repository which demonstrates the performance impact with lots of forms, feel free to take a look!: https://github.com/densitylabs/blog-reference-examples/tree/master/redux-in-forms

In recent years, we have learned to use Redux with simple applications like todo-lists or forms, but are these a good example? What if our application has grown considerably?

// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}
// Basic contact form
const Form = ({
  name,
  email,
  message,
  setFieldValue,
}) => {
  return (
    <div className="form">
      <label>
        Name:
        <input
          id="name"
          type="text"
          value={name}
          onChange={e => setFieldValue('name', e.target.value)}
        />
      </label>
      <br />
      <label>
        E-mail:
        <input
          id="email"
          type="email"
          value={email}
          onChange={e => setFieldValue('email', e.target.value)}
        />
      </label>
      <br />
      <label>
        Message:
        <textarea
          id="message"
          value={message}
          onChange={e => setFieldValue('message', e.target.value)}
        />
      </label>
      <br />
      <button type="submit">Send your message</button>
    </div>
  );
}

In this case, we are just reaching our single reducer when dispatching an action:

This may be “OK” for small apps but the latency will continue to increase as our app grows. Now, imagine that we have 50 reducers:

We will be hitting all the reducers on EVERY SINGLE KEYSTROKE.

As Dan Abramov says, forms are ephemeral and local. The redux state is intended to be global. Using a local state is fine, and if we need to share these values, we can lift up your state to the closest common ancestor.Handling the state locally

This is the same form using a local state:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
      email: '',
      message: ''
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Name:
          <input
            name="name"
            type="text"
            value={this.state.name}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          E-mail:
          <input
            name="email"
            type="email"
            value={this.state.email}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          Message:
          <textarea
            name="message"
            type="text"
            value={this.state.comments}
            onChange={this.handleInputChange}
          />
        </label>
      </form>
    );
  }
}

With this approach we get the following benefits:

  1. No need to hit any reducer

  2. Better performance. Plus, this won’t be affected even if the app continues to grow (having more reducers)

But, what if we want to have more forms? Do we need copy-paste the handleInputChange function for each form? Or what if we need to run validations? Is there a way to avoid all this boilerplate code?

The answer to these questions is a nice alternative: Formik.

Formik does all this magic for us under the hood. I won’t cover how to use Formik in this post since it provides good documentation. However, I would like to mention that Formik + Yup will solve most of your problems.

Are you interested in looking at Formik in more depth? Let me know in the comments!

Conclusion

Using the local state on React is usually better. You should use Redux for complex state transitions, when you need to keep track of the changes or when it matters globally.

...

I created this repository which demonstrates the performance impact with lots of forms, feel free to take a look!: https://github.com/densitylabs/blog-reference-examples/tree/master/redux-in-forms

Hire top-tier talent

Guadalajara

Werkshop - Av. Acueducto 6050, Lomas del bosque, Plaza Acueducto. 45116,

Zapopan, Jalisco. México.

Texas
17350 State Hwy 249, Ste 220 #20807,

Houston, Texas 77064 US.

© Density Labs. All Right reserved. Privacy policy and Terms of Use.

Hire top-tier talent

Guadalajara

Werkshop - Av. Acueducto 6050, Lomas del bosque, Plaza Acueducto. 45116,

Zapopan, Jalisco. México.

Texas
17350 State Hwy 249, Ste 220 #20807,

Houston, Texas 77064 US.

© Density Labs. All Right reserved. Privacy policy and Terms of Use.

Hire top-tier talent

Guadalajara

Werkshop - Av. Acueducto 6050, Lomas del bosque, Plaza Acueducto. 45116,

Zapopan, Jalisco. México.

Texas
17350 State Hwy 249, Ste 220 #20807,

Houston, Texas 77064 US.

© Density Labs. All Right reserved. Privacy policy and Terms of Use.