简体   繁体   中英

How to conditionally render component in <Field> of redux-form

In my code, was trying to render a <DatePicker> in <Field> component of Redux Form, via a function called renderDatePicker() . This function is linked to handleClick() function where the state variable isOpen is set to true .

So ideally, onClick should render the <DatePicker> as it is set to visible. But code doesn't update anything. Where am I doing wrong here?

Note: Rendering <DatePicker> alone directly without the help of <Field component=...> , works fine.

For debugging, complete code is in CodeSandbox,

编辑 Redux 表单 - 简单示例

SimpleForm.js

import React from "react";
import { reduxForm } from "redux-form";
import { Field } from "redux-form";
import DatePicker from "react-mobile-datepicker";

class SimpleForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      time: new Date(),
      isOpen: false
    };
    this.handleClick = this.handleClick.bind(this);
  }

  renderDatePicker = () => (
    <DatePicker
      value={this.state.time}
      isOpen={this.state.isOpen}
      onSelect={this.handleSelect}
      onCancel={this.handleCancel}
    />
  );

  handleClick() {
    this.setState({ isOpen: true }, function() {
      console.log(this.state.isOpen);
    });
  }

  handleCancel = () => {
    this.setState({ isOpen: false });
  };

  handleSelect = time => {
    this.setState({ time, isOpen: false });
  };

  render() {
    return (
      <div>
        <button className="select-btn" onClick={this.handleClick}>
          select time
        </button>
        <Field
          name="date"
          type="date"
          component={this.renderDatePicker}
          label={"date"}
        />
      </div>
    );
  }
}

export default reduxForm({
  form: "simple" // a unique identifier for this form
})(SimpleForm);

The reason for this behavior lies in the implementation of react-form's Field component. It does a shallow compare of all its properties to decide whether it should rerender. You can change your component's state as much as you like, the reference to this.renderDatePicker won't change.

Field passes properties including an onChange handler and the current value into the field's component stateless function call to notify of changes, but this doesn't really apply here because your toggle button is outside of the field.

So one option that comes to my mind is to move your button into the rendered field and then call onChange(!value) .

The easier yet dirtier option would be to use an arrow function in your component property: component={() => this.renderDatePicker()} - this instance changes with every re-render of your SimpleForm (ie if the state changes), so it comes with a cost, but depending on the complexity of your application the cost is negligible. To mitigate the impact, you could implement shouldComponentUpdate (just like redux-form's Field does) to decide whether it should rerender or not, based on the current and next isOpen state.

Check this bit in redux-form for more details: https://github.com/erikras/redux-form/blob/master/src/createField.js#L44

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM