即使在状态更改后组件也不会更新

Posted

技术标签:

【中文标题】即使在状态更改后组件也不会更新【英文标题】:Component not updating even after state is changed 【发布时间】:2021-07-26 12:57:39 【问题描述】:

我有这个朋友组件,我在数据库中搜索用户的朋友(存储在用逗号分隔的字符串中)并将它们显示在可滚动的 div 中。您还可以添加新朋友。数据库和后端一切正常。但是,当状态改变时,组件不会被重新渲染。它依赖于“allFriends”,因此它应该在更新时重新渲染。你们知道这里发生了什么吗?我猜它与异步性有关,但我似乎无法确定它。我为每个代码块添加了注释,以使其更易于阅读。

import React,  useState, useEffect  from 'react';
import SingleFriend from './SingleFriend';
import './friends.css';

const Friends = (username) => 
    const [allFriends, setAllFriends] = useState([]);
    const [unsortedFriends, setUnsortedFriends] = useState([]);
    const [friendFilter, setFriendFilter] = useState('');
    const [friendSearch, setFriendSearch] = useState('');
//-----------------------------------------------------------------------------------
    // Start fetching friends on component mount
//-----------------------------------------------------------------------------------
    useEffect(() => 
        fetchFriends();
    , [])
//-----------------------------------------------------------------------------------
    // Sort the friends when fetching has finished/unsortedFriends has updated
//-----------------------------------------------------------------------------------
    useEffect(() => 
        const onlineFriends = [];
        const offlineFriends = [];
        unsortedFriends.forEach(f => 
            if (f.status === 'online') 
                onlineFriends.push(f)
             else 
                offlineFriends.push(f)
            
        )
        setAllFriends(onlineFriends.concat(offlineFriends));
    ,[unsortedFriends])
//-----------------------------------------------------------------------------------
    // Get the string of friends that is stored in the database for the user 
    // Convert to array of friends
    // Pass the array to 'fetchFriendData()'
//-----------------------------------------------------------------------------------
    const fetchFriends = () => 
        let allFriendNames = [];
        fetch(`http://localhost:8000/getFriends?username=$username`)
        .then(res => res.json())
        .then(friends => 
            if (friends !== null && friends !== '') 
                allFriendNames = friends.split(',');
                fetchFriendData(allFriendNames);
            
        )
    
//-----------------------------------------------------------------------------------
    // Search the database for each of the user's friends
    // Return those users, and add their username & online status to a temporary array
    // Assign that array to the unsortedFriends useState hook
//-----------------------------------------------------------------------------------
    const fetchFriendData = (allFriendNames) => 
        let allF = [];
        for (let friend of allFriendNames) 
            fetch(`http://localhost:8000/findFriend?username=$friend`)
            .then(res => res.json())
            .then(user => 
                if (user.socketid) 
                    allF.push(name: user.username, status: 'online')
                 else 
                    allF.push(name: user.username, status: 'offline')
                
            )
            .catch(err => console.log(err))
        
        document.querySelector('.addFriendInput').value = '';
        setUnsortedFriends(allF);
    
//-----------------------------------------------------------------------------------
    // Called on button press to add friend
//-----------------------------------------------------------------------------------
    const addFriend = () => 
        let friendList = '';
        let friendArray = [];
//-----------------------------------------------------------------------------------
        // Search the database to check if the name that was 
        // entered matches any users in the databse
//-----------------------------------------------------------------------------------
        fetch(`http://localhost:8000/findFriend?username=$friendSearch`)
            .then(res => res.json())
            .then(user => 
                if (user.username) 
//-----------------------------------------------------------------------------------
                    // If friend exists, grab the user's friend list string
                    // Make a temporary string and array with the new friend
//-----------------------------------------------------------------------------------
                    fetch(`http://localhost:8000/getFriends?username=$username`)
                    .then(res => res.json())
                    .then(friends => 
                        if (friends !== null && friends !== '') 
                            friendArray = friends.split(',');
                            if (friendArray.includes(friendSearch)) 
                                throw new Error('Problem getting friend')
                             else 
                                friendArray.push(friendSearch);
                                friendList = friends.concat(`,$friendSearch`);
                            
                         else 
                            friendList = friendSearch;
                            friendArray = [friends];
                        
//-----------------------------------------------------------------------------------
                        // Update the user's friend list with the new friends string
                        // Pass the updated friends array to 'fetchFriendData'
//-----------------------------------------------------------------------------------
                        fetch('http://localhost:8000/addFriend', 
                            method: 'put',
                            headers: 'Content-Type': 'application/json',
                            body: JSON.stringify(
                                username: username,
                                friendlist: friendList
                            )
                        )
                        .then(fetchFriendData(friendArray))
                        .catch(err => console.log(err))
                    )
                    .catch(err => console.log(err))
                
            )
            .catch(err => console.log(err))

    

    return (
        <div className='friendsContainer'>
            <div className='friendsSection'>
                <h2>Friends</h2>
                <input onChange=(e) => setFriendFilter(e.target.value) type='text' placeholder='Enter a username'/>
                <div className='friendsListContainer'>
                
                    allFriends.length
                    ?
                    <div className='friendsList'>
                    
//-----------------------------------------------------------------------------------
                        // Map through the user's friends
                        // Return a single friend div w/ their username and status
//-----------------------------------------------------------------------------------                        
                        allFriends.map(f => 
                            if (f.name.toLowerCase().includes(friendFilter.toLowerCase())) 
                                return <SingleFriend key=f.name name=f.name status=f.status/>
                             else return null
                        )
                    
                    </div>
                    : <h4 className='noFriends'>No friends have been added</h4>
                
                </div>
                <div className='addFriend'>
                    <h3 className='addFriendText' >Add a friend</h3>
                    <input className='addFriendInput' onChange=(e) => setFriendSearch(e.target.value) type='text' placeholder='Enter a username'/>
                    <button onClick=addFriend >Add</button>
                </div>
            </div>
        </div>
    )


export default Friends;

【问题讨论】:

嗨!请使用tour(您将获得徽章!),环顾四周,并阅读help center,尤其是How do I ask a good question?,我还推荐Jon Skeet 的Writing the Perfect Question。请将问题中的代码减少为minimal reproducible example,最好是使用堆栈片段([&lt;&gt;] 工具栏按钮)可运行的代码。 Stack Snippets 支持 React,包括 JSX; here's how to do one. 首先,setUnsortedFriends(allF); 将永远是setUnsortedFriends([]);,因为您有一个 fetch() 的 for 循环,并且在您调用 setUnsortedFriends() 之后它们都会完成很长时间。您需要使用 Promise.all() 或 async / await。 核心问题的主要参考:***.com/questions/23667086/… 【参考方案1】:

你需要等待获取响应数据

   const fetchFriendData = async (allFriendNames) => 
        let allF = [];
        for (let friend of allFriendNames) 
            const response = await fetch(`http://localhost:8000/findFriend?username=$friend`)
            const user = await response.json()

            if (user.socketid) 
                allF.push(name: user.username, status: 'online')
             else 
                allF.push(name: user.username, status: 'offline')
            
        
       document.querySelector('.addFriendInput').value = '';
       setUnsortedFriends(allF);
    

【讨论】:

以上是关于即使在状态更改后组件也不会更新的主要内容,如果未能解决你的问题,请参考以下文章

即使调用了渲染函数中的 console.log,组件也不会在状态更改时重新渲染

即使从父组件传递函数后也无法从子组件更改状态

商店状态更改时反应组件不更新

React 功能组件在状态更改后不更新

在 React 中通过更改父级的道具来更新子组件

reactjs - 状态更改后组件不呈现[重复]