简体   繁体   中英

React change Input elements based on state variable

I'm trying to change the Inputs that I display based on id state variable that the user can select in a dropdown. It's odd, but after changing the select ID, the Inputs are rendered properly, but it is setting the previous Input value to the new Input. Also, the submit is validating Input that does not exist.

import React, { useState, useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { Button, Form, Label, Input } from "reactstrap";

const App = () => {
  const [id, setID] = useState(1);
  const units = [
    { UnitID: 1, UnitName: "101" },
    { UnitID: 2, UnitName: "102" },
    { UnitID: 3, UnitName: "103" },
    { UnitID: 4, UnitName: "104" }
  ];

  useEffect(() => {
    console.log("ID was updated");
  }, [id]);

  const {
    handleSubmit,
    control,
    setValue,
    formState: { errors }
  } = useForm();

  const handleChangeDeposit = (id) => {
    setValue("id", parseInt(id));
    setID(parseInt(id));
  };

  const resetFields = () => {
    setValue("transactionComment", "");
    setValue("unitID", 0);
  };

  const renderTest = () => {
    switch (parseInt(id)) {
      case id === 3 || id === 5:
        resetFields();
        return (
          <div className="col-sm-3">
            <Label for="transactionComment" className="mr-sm-10">
              Comment
            </Label>
            <Controller
              name="transactionComment"
              control={control}
              rules={{ required: true }}
              defaultValue={""}
              render={({ field }) => (
                <Input {...field} type="text" id="transactionComment" />
              )}
            />
            {errors.transactionComment && (
              <span style={{ color: "red" }} role="alert">
                required
              </span>
            )}
          </div>
        );
      case 11:
        resetFields();
        setValue("transactionComment", "Laundry Room");
        return (
          <div className="col-sm-3">
            <Label for="transactionComment" className="mr-sm-10">
              Comment
            </Label>
            <Controller
              name="transactionComment"
              control={control}
              defaultValue={"Laundry Room"}
              render={({ field }) => (
                <Input
                  {...field}
                  type="text"
                  id="transactionComment"
                  readOnly
                />
              )}
            />
          </div>
        );
      default:
        resetFields();
        return (
          <div className="col-sm-3">
            <Label for="unitID" className="mr-sm-10">
              Unit
            </Label>
            <Controller
              name="unitID"
              control={control}
              rules={{ required: true }}
              defaultValue={0}
              render={({ field }) => (
                <Input {...field} type="select" id="unitID">
                  <option value="0">Select</option>
                  {units.map((obj) => {
                    return (
                      <option key={obj.UnitID} value={obj.UnitID}>
                        {obj.UnitName}
                      </option>
                    );
                  })}
                </Input>
              )}
            />
            {errors.unitID && (
              <span style={{ color: "red" }} role="alert">
                required
              </span>
            )}
          </div>
        );
    }
  };

  const submitForm = (data) => {
    if ([3, 5].includes(id) && data.transactionComment === "") {
      alert("Transaction Comment is require");
      return;
    }
    if (![3, 5].includes(id) && parseInt(data.unitID) === 0) {
      alert("Unit is required.");
      return;
    }
    alert("Updated!");
  };

  return (
    <div className="row">
      <div className="col-sm-12 col-md-12 col-xl-12">
        <Form onSubmit={handleSubmit(submitForm)}>
          <div className="row">
            <div className="col-sm-3">
              <Label for="id" className="mr-sm-10">
                Select
              </Label>
              <Controller
                name="id"
                control={control}
                rules={{ required: true }}
                defaultValue={1}
                render={({ field }) => (
                  <Input
                    {...field}
                    type="select"
                    id="id"
                    onChange={(e) => handleChangeDeposit(e.target.value)}
                  >
                    <option value="0">Select</option>
                    <option value="3">Option 3</option>
                    <option value="5">Option 5</option>
                    <option value="11">Option 11</option>
                    <option value="15">Others</option>
                  </Input>
                )}
              />
              {errors.id && (
                <span style={{ color: "red" }} role="alert">
                  required
                </span>
              )}
            </div>
            {renderTest()}
            <div className="col-sm-3">
              <Label for="memo" className="mr-sm-10">
                Memo
              </Label>
              <Controller
                name="memo"
                control={control}
                render={({ field }) => (
                  <Input
                    {...field}
                    type="text"
                    name="memo"
                    placeholder="12345"
                  />
                )}
              />
            </div>
          </div>
          <Button type="submit">Update</Button>
        </Form>
      </div>
    </div>
  );
};

export default App;

Here is the SandBox: https://codesandbox.io/s/serene-greider-z3xpd?file=/src/App.js:0-5426

Thanks

Issue

The issue is in your renderTest function, you've a malformed switch case.

const renderTest = () => {
  switch (parseInt(id)) {
    case id === 3 || id === 5:
      ...

    case 11:
      ...

    default:
      ...
  }
};

id === 3 || id === 5 id === 3 || id === 5 resolves to a boolean but you are switching on id which is one of the values 0 , 3 , 5 , 11 , and 15 . Since none of the id values is true/false the default case is rendered.

When submitForm is invoked the "comment" validation is checked.

if ([3, 5].includes(id) && data.transactionComment === "") {
  alert("Transaction Comment is require");
  return;
}

Solution

Fix the switch statement to use two distinct cases for id 3 and 5.

const renderTest = () => {
  switch (parseInt(id)) {
    case 3:
    case 5:
      ...

    case 11:
      ...

    default:
      ...
  }
};

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