skip to Main Content

I encountered the following warning in my react project.

Warning: Cannot update a component (App) while rendering a different
component (TattooForm).

Here’s a brief overview of the workflow for my TattooForm props.

  • I have a parent component App that passes state to a child component TattooForm via props.
  • The TattooForm component has an image upload feature where the user selects a body part, and uploads an image. I updated the state in the parent component (App) to pass it again to another child component.

Parent App.jsx

function App() {
    const [uploadedImages, setUploadedImages] = useState({});

    const handleUploadedImages = (newImages) => {
        setUploadedImages(newImages);
    };

    return (
        <div>
            <TattooForm handleUploadedImages={handleUploadedImages} />
            <Experience uploadedImages={uploadedImages}/>
        </div>
    );
}

Child Tattoo.jsx

const TattooForm = ({ handleUploadedImages }) => {
    const [selectedBodyPart, setSelectedBodyPart] = useState("");

    const handleImageChange = (e) => {
        const file = e.target.files[0];
        if (file) {
            const imageUrl = URL.createObjectURL(file);
            setSelectedBodyPart(imageUrl); // Local state update

            // Here I am calling the parent function to update the parent state
            handleUploadedImages({ [selectedBodyPart]: imageUrl });
        }
    };

    return (
        <div>
            <input type="file" onChange={handleImageChange} />
        </div>
    );
};

2

Answers


  1. Chosen as BEST ANSWER
    const TattooForm = ({ handleUploadedImages, imageUrl }) => {
        const [pendingImages, setPendingImages] = useState(null);
    
        useEffect(() => {
            if (pendingImages) {
               handleUploadedImages(pendingImages); // I Passed updates to parent after render
             }
         }, [pendingImages, handleUploadedImages]);
    
        const onTattooUpload = (event) => {
            if (!selectedBodyPart) {
                alert("Please select a body part first.");
                return;
             }
            const file = event.target.files[0];
            if (file) {
                const tempImageUrl = URL.createObjectURL(file);
    
            // Update the state and call the parent handler inside an event handler
                   setUploadedImages((prevImages) => {
                       const newImages = { ...prevImages, [selectedBodyPart]: 
                             tempImageUrl };
                       setPendingImages(newImages); // Store pending updates to be passed to parent later
                       return newImages;
                   });
            } return;
        };
    
        return (
            <div>
                <input type="file" onChange={handleImageChange} />
            </div>
        );
    };
    

  2. You are syncronously requesting a state update in TattooForm with:

    setSelectedBodyPart(imageUrl); // Local state update
    

    And immediately request for a state update in its parent with:

    // Here I am calling the parent function to update the parent state
    handleUploadedImages({ [selectedBodyPart]: imageUrl });
    

    So you are indeed trying to update two components at the same time, while one in containing the other.
    I think in this case React can’t "know" how to reconcile both update and that’s probably why you’re getting this warning.

    I suggest you only call the parent update, let the parent compute the imageUrl and then forward it to the child using props:

    Parent App.jsx

    function App() {
        const [imageUrl, setImageUrl] = useState('');
        
        const handleUploadedImages = (file) => {
            const imageUrlFromFile = URL.createObjectURL(file);
            setImageUrl(imageUrlFromFile);
    
        };
    
        return (
            <div>
                <TattooForm handleUploadedImages={handleUploadedImages} imageUrl={imageUrl} />
                <Experience uploadedImages={imageUrl}/>
            </div>
        );
    }
    

    Child Tattoo.jsx

    const TattooForm = ({ handleUploadedImages, imageUrl }) => {
    
    
        const handleImageChange = (e) => {
            const file = e.target.files[0];
            if (file) {
    
                // Here I am calling the parent function to update the parent state
                handleUploadedImages(file);
            }
        };
    
        return (
            <div>
                <input type="file" onChange={handleImageChange} />
            </div>
        );
    };
    

    TattooForm most certainely does not require a state, this could not work:

    setSelectedBodyPart(imageUrl); // Local state update
    // selectedBodyPart not  yet updated
    handleUploadedImages({ [selectedBodyPart]: imageUrl });
    

    and if it worked would be quivalent to this:

    handleUploadedImages({ [imageUrl ]: imageUrl });
    

    Which makes no sense.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search