组件正在更改 Select 的非受控值状态以进行控制

Pet*_*zov 5 javascript typescript reactjs material-ui

我正在尝试创建一个编辑表单来按 ID 编辑数据库中的数据。我试过这个:

    import React, {FormEvent, useEffect, useState} from "react";
    import TextField from "@material-ui/core/TextField";
    import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
    import {
      TicketFullDTO,
      TicketStatusTypesDTO,
    } from "../../service/support/types";
    import {
      getTicket,
      getTicketStatusTypes,
      updateTicket,
    } from "../../service/support";
    import { useHistory, useParams } from "react-router-dom";
    import InputLabel from "@mui/material/InputLabel";
    import Select from "@mui/material/Select";
    import MenuItem from "@mui/material/MenuItem";
    import { FormControl } from "@mui/material";
    import { Moment } from "moment";
    import { RouteParams } from "../../service/utils";
       
    export default function TicketProfile(props: any) {
      const classes = useStyles();
      let history = useHistory();
      let requestParams = useParams<RouteParams>();

      const [status, setStatus] = useState<string>("");
      const [submitDate, setSubmitDate] = useState<Moment | null>(null);
      const [ticket, setTicket] = useState<TicketFullDTO>();
    
      const formSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        console.log(e);

        updateTicket(requestParams.id, data)
          .then(({ data }) => {
            console.log(data.title);
            history.replace("/support");
          })
          .catch((err) => {
            console.log(err);
          });
      };
    
      const [ticketCategoriesList, setTicketCategoriesList] = useState<
        TicketCategoryTypesDTO[]
      >([]);
      const [ticket, setTicket] = useState<TicketFullDTO>();
            
      const getSingleTicket = async () => {
        getTicket(requestParams.id)
          .then(({ data }) => {
            setTicket(data);
          })
          .catch((error) => {
            console.error(error);
          });
      };
    
      const [ticketStatusList, setTicketStatusList] = useState<
        TicketStatusTypesDTO[]
      >([]);
    
      useEffect(() => {
        ticketStatusData();
        getSingleTicket();
      }, []);
    
      const ticketStatusData = async () => {
        getTicketStatusTypes()
          .then((resp) => {
            setTicketStatusList(resp.data);
          })
          .catch((error) => {
            console.error(error);
          });
      };
    
      return (
        <Container>
            <form onSubmit={onSubmit}>

                          .........

                          <TextField
                            value={ticket?.title}
                            id="title"                                             
                            onChange={({ target: { value } }) => {
                              setTicket({ ...ticket, title: value });
                            }}
                          />

                          .........

                          <FormControl>
                            <TextField
                              label="Submit Date"
                              id="submit-date"
                              type="date"
                              defaultValue={ticket?.submitDate}                             
                              //@ts-ignore
                              onInput={(e) => setSubmitDate(e.target.value)}
                            />
                          </FormControl>
                       
                          ..........

                            <Select
                              labelId="status-label"
                              id="status-helper"
                              value={ticket?.status}
                              onChange={(e) => setStatus(e.target.value)}
                              required
                            >
                              {ticketStatusList.map((element) => (
                                <MenuItem value={element.code}>
                                  {element.name}
                                </MenuItem>
                              ))}
                            </Select>
                          </FormControl>

                         ...........
                      
                          <Button
                            type="submit"
                          >
                            Update Ticket
                          </Button>                       
    
        </Container>
      );
    }


.....


export async function updateTicket(
    id: string,
    data: TicketFullDTO
): Promise<AxiosResponse<TicketFullDTO>> {
  return await axios.post<TicketFullDTO>(
      `${baseUrl}/management/support/tickets/ticket/${id}`,
      {
        data,
      }
  );
}

export interface TicketFullDTO {
    id?: number,
    title?: string,
    status?: string,
    submitDate?: Moment | null
}
Run Code Online (Sandbox Code Playgroud)

我在 Chrome 控制台中收到错误:

MUI: A component is changing the uncontrolled value state of Select to be controlled. Elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled Select element for the lifetime of the component. The nature of the state is determined during the first render. It's considered controlled if the value is not 不明确的.

Select应使用ticket?.status列表中的值来选择 的值ticketStatusList,但在渲染 UI 内容之前数据对象未运行,并且未选择“选择”下拉列表中的值。

你知道我该如何解决这个问题吗?

Mor*_*hai 12

valueReact 通过检查第一次渲染时是否设置来确定组件是否受控制。defaultValue只能用于不受​​控制的组件。

undefined由于您正在使用受控组件,因此您必须提供除prop之外的默认值value

<Select
    labelId="status-label"
    id="status-helper"
    value={ticket?.status ?? null}
    onChange={(e) => setStatus(e.target.value)}
    required
>
Run Code Online (Sandbox Code Playgroud)

文档中有关此主题的更多信息。


小智 2

尝试这个

                            <Select
                              labelId="status-label"
                              id="status-helper"
                              value={status}
                              onChange={(e) => setStatus(e.target.value)}
                              required
                            >
Run Code Online (Sandbox Code Playgroud)

并将status票证与ticket状态同步

      const [status, setStatus] = useState<string>("");
      const [submitDate, setSubmitDate] = useState<Moment | null>(null);
      const [ticket, setTicket] = useState<TicketFullDTO>();
      React.useEffect(() => setTicket(previousTicket => 
          ({ ...previousTicket, status })), [status]);
Run Code Online (Sandbox Code Playgroud)