2

I have an edit caption of a post feature on my app. I am fetching a get request and then save that data in a state that will display on screen. The problem here is that it take a few second to load that data on screen. After editing the caption, which I have a onChange function that will update the state with the new edited caption. The new edited caption is followed by a put request that will update the caption of the post. The problem here is that I am getting an error saying to change it to either a controlled or uncontrolled state. What is the right way of doing it?

Edit: For some reason, the error isn't showing on the console now with the same code I had previously without changes. So I guess that problem is fixed? But like I mentioned before, the caption would show up empty and then show the value of the caption 2 seconds after. Is there a way to show it instantly? Im assuming it not possible since It need to make a get request first and then store the data in the state, right?

The error I'm getting

Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

Below is my code

const PostDetail = () => {
    const navigate = useNavigate();
    const [inputs, setInputs] = useState({ caption: "" });
    const { id } = useParams();

    // once data is fetched, update the edited caption to the post
    useEffect(() => {
        const fetchDetails = async () => {
            const res = await api.get(`/post/${id}`)
                .catch((error) => console.log(error.message))
            const data = await res.data;
            return data;
        }
        fetchDetails()
            .then((data) => {
                setInputs({
                    caption: data.post.caption
                });
            });
    }, [id]);


    const sendRequest = async () => {
        const res = await api.put(`/post/update/${id}`, {
            caption: inputs.caption
        })
            .catch(error => console.log(error));
        const data = await res.data;
        return data;
    }

    const handleSubmit = (e) => {
        e.preventDefault();
        console.log(inputs);
        sendRequest()
            .then((data) => console.log(data))
            .then(() => navigate('/myposts'))
    }

    const handleChange = (e) => {
        setInputs({ caption: e.target.value })
    }

    return (
        <div>
            {inputs &&
                <form onSubmit={handleSubmit}>
                    <Box display="flex" flexDirection="column" alignItems="center" justifyContent="center" boxShadow=" 10px 10px 20px #ccc" maxWidth={500} margin="auto" padding={3} marginTop={10} borderRadius={5}>
                        <Typography fontWeight={"bold"} padding={3} textAlign={"center"} fontSize={22} fontFamily="georgia">Edit Your Post</Typography>
                        <InputLabel sx={{ mb: 1, mt: 2, fontSize: 15 }}>Caption</InputLabel>
                        <TextField value={inputs.caption} name="caption" onChange={handleChange} fullWidth />
                        <Button variant="contained" type="submit" color="warning" sx={{ marginTop: 3 }}>Submit</Button>
                    </Box>
                </form>
            }
        </div>
    )
}
Jason
  • 35
  • 5

1 Answers1

0

This warning occurs when an input's value switches from null or undefined to a real value or vice-versa.

My guess is that data.post.caption isn't present in the fetch response, so you end up setting the input's value to undefined.

This makes it an uncontrolled input.

Then you type in the field, state gets updated, and you set the input's value to a string, making it a controlled input.

Hence the warning.

If that's the case you could mitigate it by ORing it with an empty string: data.post.caption || "".

ray
  • 26,557
  • 5
  • 28
  • 27
  • data is not a global variable – Jason Jun 24 '22 at 13:51
  • I edited my post. Apparently the error is not showing now without any code changes. – Jason Jun 24 '22 at 13:56
  • I wasn't suggesting data was a global variable. I was suggesting you OR it when setting state. – ray Jun 24 '22 at 14:05
  • Is it possible the error isn't showing now because you've saved a caption on this particular post, so it now has a value on the initial load, whereas previously it didn't? – ray Jun 24 '22 at 14:06
  • Im saying data is not a global variable so it will never have a value and will always be the other value using OR. and It always had an empty caption value saved. I didnt make any code change. – Jason Jun 24 '22 at 14:08
  • What does being global have to do with you doing `setInputs({ caption: data.post.caption || ""})`? Good luck. – ray Jun 24 '22 at 15:43
  • 1
    My mistake... I thought you were referring to inside of useState. Thats why I said data is not a global variable thus it will be undefined so it wouldnt make sense to use OR with it. – Jason Jun 24 '22 at 16:29