Home > front end >  cannot change usestate to change the state of the components
cannot change usestate to change the state of the components

Time:06-22

This is code of my AddBlog Component

import React, { useState } from "react";

function AddBlogs() {

const[state, setState] = useState({blogs:[]})


const AddAnother = () => {
    return (
        <div>
            <label>Topic</label>
            <input></input>
            <button onClick={addblog}>Add another topic</button>
        </div>
    );
}

const addblog = () =>{
    setState({
        blogs:[...state.blogs,<AddAnother></AddAnother>]
    });
    console.log("Hello");
}

return (
    <div>
        <form>
            
            <div>
                <label>Topic</label>
                <input></input>
                <button onClick={addblog}>Add another topic</button>
            </div>
            <div>
                {state.blogs}
            </div>
        </form>
    </div>
);
}
export default AddBlogs;

When I click that Add another topic button AddAnother components blinks for just 0.5 second or less. Any solution for this?

CodePudding user response:

I see a couple things that will cause problems. First, when you update state, you shouldn't use the current state. Instead, you should use the setState that accepts a function with the old state as the first parameter, such as the following:

const addblog = () => {
    setState((oldState) => {
        return { blogs: [...oldState.blogs, <AddAnother />] };
    });
    console.log("Hello");
};

This won't solve your problem, though. The issue you're seeing is due to you not having a key in your array of components. So try this:

const addblog = () => {
    setState((oldState) => {
        return { blogs: [...oldState.blogs, <AddAnother key={oldState.blogs.length} />] };
    });
    console.log("Hello");
};

As David pointed out, the form is also posting, which is causing part of the problem as well.

CodePudding user response:

Because the <form> is posting. If you don't need this to be an actual <form> then remove that element entirely. But if for some reason you want to keep that element, change the button type(s):

<button type="button" onClick={addblog}>Add another topic</button>

By default a <button> is of type submit unless otherwise specified.


Edit: Additionally, as answered here, you need to change the way you're setting state to use the callback overload:

setState((oldState) => {
    return { blogs: [...oldState.blogs, <AddAnother key={oldState.blogs.length} />] };
});

In most cases it makes little difference whether you set the state directly or use the callback which sets based on previous state. The latter is often used when queueing up multiple state updates in a loop, for example. But you have an edge case here.

Your AddAnother component internally references a "stale version" of addblog which always references the original state. Changing to the callback version of setState gets around this.

Other ways around this would be to restructure your code to remove the circular dependency, refactor components into their own discrete code, make use of tools like useCallback to define functions which have dependencies on state values, etc.

  • Related