【问题标题】:Update state with Object using React Hooks使用 React Hooks 使用 Object 更新状态
【发布时间】:2021-03-16 13:42:59
【问题描述】:

我正在从Firebase 获取数据并想更新state:

const [allProfile, setAllProfile] = useState([]);
.....
const displayProfileList = async () => {
        try {

            await profile
                .get()
                .then(querySnapshot => {

                    querySnapshot.docs.map(doc => {
                        const documentId = doc.id;                        
                        const nProfile = { id: documentId, doc: doc.data()}                        
                        console.log(nProfile);//nProfile contains data
                    
                        setAllProfile([...allProfile, nProfile]);
                        console.log(allProfile); // is empty
                    }
                    );

                })
        } catch (error) {
            console.log('xxx', error);
        }
    }

【问题讨论】:

  • 状态是异步更新的。在组件的特定渲染中,状态和道具是恒定的。要查看更新的状态,组件必须重新渲染。使用useEffect 挂钩记录更新的状态值。
  • 与您的问题无关,但您不应将async-await 语法与promise-chaining 混合使用。使用其中之一,但不能同时使用。

标签: reactjs react-native react-hooks state use-state


【解决方案1】:

setAllProfile 将在迭代完成时更新状态。因此,为了让您的代码正常工作,您需要将回调函数传递给setAllProfile,如docs 所示

setAllProfile((prevState) => [...prevState, nProfile])

更新

Example demonstrating this at work

【讨论】:

  • 我注意到他确实在地图内设置了状态,但他最初的问题不是关于这个。他的问题是控制台日志更新。
【解决方案2】:

由于setAllProfile是异步方法,所以无法在setAllProfile之后立即获取更新后的值。你应该在 useEffect 中添加一个 allProfile 依赖项。

setAllProfile([...allProfile, nProfile]);
console.log(allProfile); // Old `allProfile` value will be printed, which is the initial empty array.
useEffect(() => {
  console.log(allProfile);
}, [allProfile]);

更新

const [allProfile, setAllProfile] = useState([]);
.....
const displayProfileList = async () => {
        try {

            await profile
                .get()
                .then(querySnapshot => {
                    const profiles = [];

                    querySnapshot.docs.map(doc => {
                        const documentId = doc.id;                        
                        const nProfile = { id: documentId, doc: doc.data()}                        
                        console.log(nProfile);//nProfile contains data
                        profiles.push(nProfile);
                    
                    }
                    );
                    setAllProfile([...allProfile, ...profiles]);


                })
        } catch (error) {
            console.log('xxx', error);
        }
    }

【讨论】:

  • => 当我在return 上尝试显示数据时,它会显示最后一个元素:/ {allProfile.map(profile => ( <tr key={profile.id}> <td>{profile.id} </td> </tr> ))}
  • 是的,您可以在渲染中看到更新后的allProfile。这是因为一旦状态更新,渲染就会重新渲染。
  • 这个答案是一个有效的答案,应该可以工作。我认为OP所指的问题是因为关闭了通过使用先前状态修复的状态的回调函数..
  • @4est 您最初的问题是关于状态旧值的记录,这个答案回答了您的问题。您所描述的问题是由于使用先前状态时得到修复的闭包。
  • @WilliamWang - 谢谢,我现在已经测试了你的答案,而且效果很好
【解决方案3】:

您在map 内调用setState,因此创建了几个异步调用,所有这些调用都由当前的..allProfile 值调用(而不是prev => [...prev...)引用。

试试

 let arr=[]
 querySnapshot.docs.map(doc => {
                  arr.push({ id: doc.id, doc: doc.data() })
            }                                 
 setAllProfile(prev=>[...prev,  ...arr])

我不确定获取帖子的架构是如何实现的(在分页等方面,所以你可能不需要破坏...prev

【讨论】:

  • - 来自 k.s. 的回答正在按预期工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-19
  • 2020-01-29
  • 2020-11-25
  • 1970-01-01
  • 2020-05-12
  • 2019-08-08
  • 1970-01-01
相关资源
最近更新 更多