Notes on codes, projects and everything

Building Dynamic Form the hard way with React-Redux

First component

Let’s start from a component that allow the input of multiple publications. So there should always be 1 empty form for a publication, and the user can click on something to add another. Then the user should also be able to remove them as wished.

class AppWidget extends Component {
  constructor(props) {
    super(props);

    this.handle_click = props.handle_click.bind(this);
  }

  render() {
    return (
      <fieldset>
        <legend>Publications</legend>

        {this.props.publications.map((item, idx) => (
          <Publication
            key={idx}
            publication={item}
            delegate_update={this.props.handle_update.bind(this, idx)}
          />
        ))}

        <a onClick={this.handle_click} href="#">
          Add new publiations
        </a>
      </fieldset>
    );
  }
}

(I am going to show only the render function in the following examples)

So the code above is very much only for presentation purpose, nothing much to talk about. It lists all the available publications. Then there’s also a link to click so a new publication form is added to the list.

Then we have the respective container created through react-redux connect function.

export default connect(
  state => ({
    publications: state.publications || [{}]
  }),
  dispatch => ({
    handle_click(e) {
      e.preventDefault();

      dispatch(make_publication_update(this.props.publications.concat([{}])));
    },

    handle_update(position, is_delete, changes) {
      return make_publication_update(
        is_delete
          ? this.props.publications.filter((_, idx) => idx !== position)
          : this.props.publications.map(
              (_current, idx) =>
                idx === position
                  ? Object.assign({}, _current, changes)
                  : _current
            )
      );
    }
  })
)(AppWidget);

Remember in the previous page I mentioned I only call dispatch in the browser event handlers. In this case I am concatenating a new empty publication to the list, send it to the action creator, and dispatch the action.

The more interesting part is the handle_update function here. It is of the second form, which has a position required in the function parameters. I could have passed the position as a property to the component, however I decided in the end not to because the component doesn’t have to know its position to serve its purpose, plus this would allow it to be used elsewhere when it is not in a list. This is why I bound the position in before sending it in as delegate_update property.

This also indirectly makes all delegate_update property share the same function call signature, which is delegate_update(is_delete, changes)

The parameter is_delete is placed in the first because whenever a delete operations is needed it would work with only 1 argument passed in. We shall see it in action in the following Publication component.

leave your comment

name is required

email is required

have a blog?

This blog uses scripts to assist and automate comment moderation, and the author of this blog post does not hold responsibility in the content of posted comments. Please note that activities such as flaming, ungrounded accusations as well as spamming will not be entertained.

Click to change color scheme