在 React handleChange 中设置对象值的更通用方法

More generic way to set an objects value within React handleChange

我在 React 中有一个组件,我需要从被选中的单选按钮中获取一个值,然后在我的 Formik 值中的一个对象中设置该值。如果在组中选择了不同的单选按钮,我需要将先前选择的单选按钮设置为 false,是否有标准的方法可以做到这一点?我在我的 Formik 值中使用一个对象,因为该字段包含日期以及单选按钮的属性,您可以看到我使用 handleTime 将日期放入对象的位置,所以我不能只清空该字段并将新项目放入。

我目前正在我的组件中执行以下操作以更新 Formik time_frame 值。

import React, {Component} from 'react';
import {Col, Row} from 'react-bootstrap';
import Radio from "./radio";


export default class EventTimeFrame extends Component {
    state = {
        eventTimeFrame: [
            {id: 1, value: "one_off", label: "ONE OFF", checked: false},
            {id: 2, value: "recurring", label: "RECURRING", checked: false},
        ]
    }

    handleOccurance = value => {
        let timeCopy = {...this.props.values.time_frame}
        if (value.target.checked) {
            if (value.target.value === "one_off") {
                timeCopy[value.target.value] = true
                timeCopy["recurring"] = false
            } else {
                timeCopy[value.target.value] = true
                timeCopy["one_off"] = false
            }
        }
        this.props.onChange("time_frame", timeCopy)

        this.setState(prevState => ({
            eventTimeFrame: prevState.eventTimeFrame.map(
                el => el.value === value.target.value ? {...el, checked: true} : el
            )
        }))
    };

    handleTime = value => {
        let timeCopy = {...this.props.values.time_frame}
        timeCopy["start"] = new Date(value.target.value);
        this.props.onChange("time_frame", timeCopy)
    };

    render() {
        return (
            <div>
                <Row>
                    <Col>
                        <h4 className="ui centered question-header text-center">ONE OFF OR RECURRING EVENT?</h4>
                    </Col>
                </Row>
                <Row>
                    {
                        this.state.eventTimeFrame.map((timeFrame) => {
                            return (
                                <Radio name="time_frame" key={timeFrame.value}
                                       onChange={this.handleOccurance} checked={timeFrame.checked} {...timeFrame} />
                            )
                        })
                    }
                </Row>
                <Row>
                    <Col>
                        <h4 className="question-header date-text">PLEASE ENTER THE FIRST DAY OF YOUR EVENT</h4>
                    </Col>
                    <Col>
                        <input type="date" className="form-control date" name="start"
                               onChange={this.handleTime}/>
                    </Col>
                </Row>
            </div>
        )
    }
}

我觉得必须有一个标准的方法来处理这样的事情

你是对的,怀疑有更简单的方法一些反馈:

  • 不要将 eventTimeFrame 存储在状态中,常量即可。
  • 在 Formik 中使用单选输入值的标准方法是在 initialState 中为整个组定义一个值。 Formik 会将其值设置为 selected 选项。
  • 如果您使用复选框而不是单选按钮,将所有选项存储在 values 中会很好。
  • 您编写了自己的自定义 onChange 处理程序,但使用 Formik 提供的 onChange 处理程序会更简单。我只在必要时使用我自己的处理程序,例如在使用 setFieldValue()
  • 设置值之前格式化值

见下文:

Live Demo

// outside of component
const timeFrameTypes = [
  { id: "one_off", label: "ONE OFF" },
  { id: "recurring", label: "RECURRING" }
];

// in component's render function:
<Formik
  initialValues={{
    time_frame: {
      type: "",
      start: ""
    }
  }}
  onSubmit={async (values) => {
    // do something with values
  }}
>
  {({ handleSubmit }) => {
    return (
      <form onSubmit={handleSubmit}>
        <div>
          <Row>
            <Col>
              <h4 className="ui centered question-header text-center">
                ONE OFF OR RECURRING EVENT?
              </h4>
            </Col>
          </Row>
          <Row>
            {timeFrameTypes.map((timeFrameType) => {
              return (
                <Field
                  key={timeFrameType.id}
                  component={Radio}
                  name="time_frame.type"
                  id={timeFrameType.id}
                  label={timeFrameType.label}
                />
              );
            })}
          </Row>
          <Row>
            <Col>
              <h4 className="question-header date-text">
                PLEASE ENTER THE FIRST DAY OF YOUR EVENT
              </h4>
            </Col>
            <Col>
              <Field name="time_frame.start">
                {({ field }) => <input type="date" {...field} />}
              </Field>
            </Col>
          </Row>
        </div>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }}
</Formik>