简体   繁体   English

React,组件在数组状态更改后不重新渲染(与其他不同)

[英]React, component not re-rendering after change in an array state (not the same as others)

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.我已经看到了这个问题的其他答案,您必须将一个新数组传递给setImages函数,而不是先前数组的更新版本,我正在这样做,但它仍然不起作用。

(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) (有趣的是,如果我将 console.log 放在useEffect中,它会在重新渲染数组时记录文本,但页面不会显示更新的信息)

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>
    )
}

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.您正在将更新程序回调传递给 useState() 更新程序函数,该函数返回先前图像和新图像的串联,这应该返回一个新数组。

When using collection-based state variables, I highly recommend setting the key property of rendered children.使用基于集合的状态变量时,我强烈建议设置渲染子项的key属性。 Have you tried assigning a unique key to <div className="img-card"> ?.您是否尝试为<div className="img-card">分配唯一键? It appears that i.props.name is unique enough to work as a key.看来i.props.name足够独特,可以用作键。

Keys are how React associates individual items in a collection to their corresponding rendered DOM elements.键是 React 如何将集合中的单个项目与它们对应的渲染 DOM 元素相关联。 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.即使添加密钥不能解决您的问题,出于性能原因,我仍然强烈建议您保留它。

It is related to Array characteristics of javascript.它与javascript的Array特性有关。 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.希望对您有所帮助。

Ok the problem for me was the server was not sending a proper filename header so it was always null so the condition i.props.name was never true... lol sorry for the confusion.好的,对我来说问题是服务器没有发送正确的filename标头,因此它始终为空,因此条件i.props.name永远不会为真...大声笑抱歉造成混乱。

So the moral of this story is, always make sure that it's not something else in your code that causes the bad behavior before starting to look for other solutions...所以这个故事的寓意是,在开始寻找其他解决方案之前,请始终确保代码中没有其他东西导致不良行为......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM