Search code examples
reactjsreduxreact-reduxredux-form

React/Redux—Individual state for each Instance of a Component


If have a list of users and each Entry has a button »EDIT«. If the user clicks on it the following happens:

  1. request the server for the form
  2. Add the component <UserEditForm /> to the entry, what expands the entry

This works fine except one thing: If one clicks further buttons each Instance of the form receives the data of the last user form requested. That is because I have only only one userform property in the state.

So to solve this I want to exchange userform to userforms which should/could be an Object like that:

userforms: {
  <id of first instance>: { … }, //formdata
  <id of second instance>: { … },
  …
}

But since I am new to React/Redux I do not really know how to do that, or what the »right« approach, or best practice is, to actually do it.

My Idea is to create a higher Order Component like so:

import React from 'react';
import {connect} from 'react-redux';
import {uuid} from '../../helpers/uuid';

export const formdatainstance = (FormInstance) => {

  let id = null;

  class FormDataMapper extends React.Component {
    constructor (props) {
      super(props);
      id = uuid();
    }

    render () {
      //extract the formdata from the state
      //using the id
      return <FormInstance { ...this.props } />
    }
  }

  const mapStateToProps = (state) => {
    console.log(id); //is null for one run
    return {
      userforms: state.userforms
    };
  };

  return connect(mapStateToProps)(FormDataMapper);
}

So in the List component I can:

import UserEditForm from './UserEditForm';
import {formdatainstance} from './formdatainstance';

const MappedUserEditForm = formdatainstance(UserEditForm);

class List extends React.Component {
  render(){
    return (
      {users.map(user => {
        //more stuff
        <MappedUserEditForm />
        //more stuff
      })}
    );
  }
}

So my Question: Is this a good Idea? If yes what would be the proper way to do the cleanup, so when in the life cycle of the component should I delete the data from the state? Is there another way to do that, which is easier?

Thanks for Help!


Solution

  • Here's what you can do...

    import React from 'react';
    import { compose } from 'redux';
    import { connect } from 'react-redux';
    import { reduxForm } from 'redux-form';
    
    class UserEditForm extends Component {
       ...
    
       render() {
          return <form onSubmit={this.props.handleSubmit(this.props.onSubmit)}>
              ...form fields
          </form>
       }
    }
    
    const mapStateToProps = (state, ownProps) => {
       return {
          form: ownProps.formId
       }
    }
    
    export default compose(
       connect(mapStateToProps),
       reduxForm({
          //...other redux-form options
       })
    )(UserEditForm);
    

    Your ListComponent

    render() {
       return <ul>
          {this.props.users.map(user => 
             <li key={user.id}>
                 ...
                 <UserEditForm formId={'form-' + user.id} onSubmit={...} />
             </li>
          )}
       </ul>
    }
    

    This allows you to have a dynamic form name.