Home > Software engineering >  React, component not re-rendering after change in an array state (not the same as others)
React, component not re-rendering after change in an array state (not the same as others)

Time:06-20

I'm trying to make a page that gets picture from a server and once all pictures are downloaded display them, but for some reason the page doesn't re-render when I update the state.

I've seen the other answers to this question that you have to pass a fresh array to the setImages function and not an updated version of the previous array, I'm doing that but it still doesn't work.

(the interesting thing is that if I put a console.log in an useEffect it does log the text when the array is re-rendered, but the page does not show the updated information)

If anyone can help out would be greatly appreciated!

Here is my code.

 export function Profile() {
    const user = JSON.parse(window.localStorage.getItem("user"));
    const [imgs, setImages] = useState([]);
    const [num, setNum] = useState(0);
    const [finish, setFinish] = useState(false);

    const getImages = async () => {
        if (finish) return;
        let imgarr = [];
        let temp = num;
        let filename = "";
        let local = false;
        while(temp < num 30) {
            fetch("/get-my-images?id="   user.id   "&logged="   user.loggonToken   "&num="   temp)
            .then(response => {
                if(response.status !== 200) {
                    setFinish(true);
                    temp = num 30;
                    local = true;
                }
                filename = response.headers.get("File-Name");
                return response.blob()
            })
            .then(function(imageBlob) {
                if(local) return;
                const imageObjectURL = URL.createObjectURL(imageBlob);
                imgarr[temp - num] = <img name={filename} alt="shot" className="img" src={imageObjectURL}  key={temp} />
                temp  ;
            });
        }
        setNum(temp)
        setImages(prev => [...prev, ...imgarr]);
    }

    async function handleClick() {
        await getImages();
    }

    return (
        <div>
            <div className="img-container">
                {imgs.map(i => {
                    return (
                        i.props.name && <div className="img-card">
                            <div className="img-tag-container" onClick={(e) => handleView(i.props.name)}>{i}</div>
                            
                            <div className="img-info">
                                <h3 className="title" onClick={() => handleView(i.props.name)}>{i.props.name.substr(i.props.name.lastIndexOf("\\") 1)}<span>{i.props.isFlagged ? "Flagged" : ""}</span></h3>
                            </div>
                        </div>
                    )
                })}
            </div>
            <div className="btn-container"><button className="load-btn" disabled={finish} onClick={handleClick}>{imgs.length === 0 ? "Load Images" : "Load More"}</button></div>
        </div>
    )
}

CodePudding user response:

I think your method of creating the new array is correct. You are passing an updater callback to the useState() updater function which returns a concatenation of the previous images and the new images, which should return a fresh array.

When using collection-based state variables, I highly recommend setting the key property of rendered children. Have you tried assigning a unique key to <div className="img-card">?. It appears that i.props.name is unique enough to work as a key.

Keys are how React associates individual items in a collection to their corresponding rendered DOM elements. They are especially important if you modify that collection. Whenever there's an issue with rendering collections, I always make sure the keys are valid and unique. Even if adding a key doesn't fix your issue, I would still highly recommend keeping it for performance reasons.

CodePudding user response:

It is related to Array characteristics of javascript. And the reason of the console log is related with console log print moment. So it should be shown later updated for you.

There are several approaches.

const getImages = async () => {
      ... ...
        setNum(temp)
        const newImage = [...prev, ...imgarr];
        setImages(prev => newImage);
    }
const getImages = async () => {
      ... ...
        setNum(temp)
        setImages(prev => JOSN.parse(JSON.object([...prev, ...imgarr]);
    }
const getImages = async () => {
      ... ...
        setNum(temp)
        setImages(prev => [...prev, ...imgarr].slice(0));
    }

Maybe it could work. Hope it will be helpful for you.

  • Related