Home > Software design >  React input, I defined the state into initial state but still get warning changing uncontrolled to c
React input, I defined the state into initial state but still get warning changing uncontrolled to c

Time:03-18

I read the controlled and uncontrolled input from React page and follow what they recommend but somehow the warning about uncontrolled into controlled still there.

My code below is actually a page component to edit the data for the project detail. I set the values of the form to the project data after retrieve from API.

import { useState } from "react";
import { useDispatch } from "react-redux";
import {
  updateProject,
  deleteProject,
  getProjectById,
  reset,
} from "../../features/project/projectSlice";
import { useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
import { useEffect } from "react";
import { Button, Container, Form, Modal, Col, Spinner, Stack, ListGroup, Dropdown, Row } from "react-bootstrap"
import Member from "./Member";

import AddMember from "./AddMember";

function EditProject() {

  // Modal
  const [show, setShow] = useState(false);
  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);

  // Data State
  const { id } = useParams();
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const { isLoading, isError, projects, isSuccess, message } = useSelector(
    (state) => state.project
  );
  const {user} = useSelector((state)=> state.auth)

  const [code, setCode] = useState("");
  const [title, setTitle] = useState("");
  const [desc, setDesc] = useState("");
  const [users, setUsers] = useState([]);

  useEffect(() => {
    dispatch(getProjectById(id));
    if (isError) {
      console.log(message);
    }

    return () => dispatch(reset());
  }, [isError, message, dispatch]);

  useEffect(() => {
    if (isSuccess && projects) {
      setCode(projects.code);
      setTitle(projects.title);
      setDesc(projects.desc);
      setUsers(projects.users);
    }
  }, [isSuccess,projects]);

  // Data Saving
  const onSubmit = (e) => {
    e.preventDefault();
    const projectData = {
      code,
      title,
      desc,
      users: users.map((user)=> ({...user, _user: user._user._id}))
    };

    const projectChanges = {
      projectId: id,
      projectData,
    };
    console.log(projectData)
    dispatch(updateProject(projectChanges));
    navigate("/projects");
  };


  if (isLoading) {
    return (
      <Container className="mt-5" style={{ justifyContent: "center", display: "flex" }}>
        <Spinner animation="border" />
      </Container>
    )
  }

  if(user._id !== projects.manager){
    return <h5>You do not have permission to edit this project</h5>
  }

  return (
    <>
      <Container fluid="md" className="mt-5">
        <Form onSubmit={onSubmit}>
          <Stack gap={3}>
            <Form.Group>
              <Form.Label>Code</Form.Label>
              <Form.Control type="text" placeholder="Enter project codename" value={code} onChange={(e) => setTitle(e.target.value)} />
              <Form.Text className="text-muted">Codename is a short form of the project that used widely</Form.Text>
            </Form.Group>
            <Form.Group>
              <Form.Label>Title</Form.Label>
              <Form.Control type="text" rows={5} placeholder="Enter project description" value={title} onChange={(e) => setTitle(e.target.value)} />
            </Form.Group>
            <Form.Group>
              <Form.Label>Description</Form.Label>
              <Form.Control as="textarea" rows={5} placeholder="Enter project description" value={desc} onChange={(e) => setDesc(e.target.value)} />
            </Form.Group>
            <Form.Group>
              <Row className="mb-2">
                <Col className="vertical-align"><Form.Label style={{ margin: "0" }}>Team Member</Form.Label></Col>
                <Col md="auto"><Button variant="primary" onClick={handleShow}>Add People</Button></Col>
              </Row>
              <ListGroup>
                {users && users.map((user,index) => <Member key={user._user._id}  user={user} setUser={setUsers} users={users} index={index} />)}
              </ListGroup>
            </Form.Group>
            <Row className="align-items-end">
              <Col className="d-flex justify-content-end gap-2">
                <Button variant="danger" className="px-3">Delete</Button>
                <Button type="submit" className="px-5">Submit</Button>
              </Col>
            </Row>
          </Stack>
        </Form>
      </Container>
      <AddMember show={show} onHide={handleClose} />
    </>
  );
}

export default EditProject;

I found that the code below is source of the warning, I did remove and the warning gone. I want to know what exactly my mistake that cause the warning and the solution for this.

useEffect(() => {
    if (isSuccess && projects) {
      setCode(projects.code);
      setTitle(projects.title);
      setDesc(projects.desc);
      setUsers(projects.users);
    }
  }, [isSuccess,projects]);

Here is sample of API retrieved,

    {
        "_id": "abc123",
        "code": "PROJ",
        "title": "Project",
        "desc": "Project detail.",
        "users": [
            {
                "_user": "1",
                "role": "UI/UX Designer",
                "status": "Active"
            },
            {
                "_user": "2",
                "role": "Software Engineer",
                "status": "Active"
            }
        ],
    }

CodePudding user response:

This is most likely happening because one of the properties of projects is undefined.

Try checking that each property is not undefined before setting it:

useEffect(() => {
  if (isSuccess && projects) {
    if (projects.code !== undefined) {
      setCode(projects.code);
    }
    if (projects.title !== undefined) {
      setTitle(projects.title);
    }
    if (projects.desc !== undefined) {
      setDesc(projects.desc);
    }
    if (projects.users !== undefined) {
      setUsers(projects.users);
    }
  }
}, [isSuccess, projects]);

Or, you could use nullish coalescing:

useEffect(() => {
  if (isSuccess && projects) {
    setCode(projects.code ?? '');
    setTitle(projects.title ?? '');
    setDesc(projects.desc ?? '');
    setUsers(projects.users ?? []);
  }
}, [isSuccess, projects]);
  • Related