为啥当我使用 React 钩子和 React 上下文添加新帖子时,我的状态会替换我的帖子

Posted

技术标签:

【中文标题】为啥当我使用 React 钩子和 React 上下文添加新帖子时,我的状态会替换我的帖子【英文标题】:Why is my state replacing my posts when I add a new one using React hooks and React context为什么当我使用 React 钩子和 React 上下文添加新帖子时,我的状态会替换我的帖子 【发布时间】:2021-05-07 11:59:06 【问题描述】:

我正在创建一个新应用,我希望能够将更新发布给我的朋友。一个微博网站。

我想学习如何使用 React 钩子和 React 的上下文 API 更新应用程序。我创建了以下将状态作为值的提供程序...我希望能够添加一个新帖子,然后更新该州的帖子,这样我就不必再次获取数据库(使用 firestore)我是真的想给自己节省一个对数据库的调用......

基本上,当我在状态中调用 createNewPost 时,我希望能够更新状态的当前帖子部分:state.posts 但是当我在 API 调用成功后更新状态时,我的整个帖子数组被替换因为某些原因。不知道我可能做错了什么......

import  createContext, useState  from 'react';
import  createDoc, getWhere  from '../utils/database/db';

export const PostDataContext = createContext();

const SetDataContextProvider = ( children ) => 
    const [state, setState] = useState(
        posts: [],
        timelinePosts: [],
        createNewPost: async (collection, payload) => 
            const doc = await createDoc(collection, payload)
            payload.id = doc?.doc?.id;
            updateStatePosts(payload);
            return doc;
        ,
        getPostsByUserId: async (userId) => 
            const dataReceived = await getWhere('/posts', userId, 'userId')
            setState( ...state, posts: dataReceived )
        
    );
    const updateStatePosts = (payload) => 
        console.log('why is state posts empty?!', state);
        setState( ...state, posts: [payload, ...state.posts] )
    
    return <PostDataContext.Provider value=state>
        children
    </PostDataContext.Provider>


export default SetDataContextProvider;

【问题讨论】:

你是怎么把updateStatePosts传下来的? 我只是从createNewPost 调用它,但@Drew Reese 帮助我指出了正确的方向...... 【参考方案1】:

如果我不得不猜测,我会说您在您的状态中使用的 updateStatePosts 函数中有一个陈旧的初始空 posts 状态外壳。您可以使用功能状态更新来访问要更新的先前状态。功能状态更新允许您从以前的状态进行更新,而不是更新被排队/包含在其中的状态。

const SetDataContextProvider = ( children ) => 
    const [state, setState] = useState(
        posts: [],
        timelinePosts: [],
        createNewPost: async (collection, payload) => 
            const doc = await createDoc(collection, payload)
            payload.id = doc?.doc?.id;
            updateStatePosts(payload);
            return doc;
        ,
        getPostsByUserId: async (userId) => 
            const dataReceived = await getWhere('/posts', userId, 'userId')
            setState(prevState => (
                ...prevState, // <-- preserve any previous state
                posts: dataReceived
            ))
        
    );

    const updateStatePosts = (payload) => 
        setState(prevState => ( // <-- previous state to this update
            ...prevState,
            posts: [payload, ...prevState.posts],
         ));
    ;

    return <PostDataContext.Provider value=state>
        children
    </PostDataContext.Provider>

【讨论】:

【参考方案2】:

这个函数是错误的:

const updateStatePosts = (payload) => 
        console.log('why is state posts empty?!', state);
        setState( ...state, posts: [payload, ...state.posts] )
    

您正在为您的状态正确使用扩展运算符,但 posts 被直接替换。您可能想使用以下setState

setState( ...state, posts: [...payload,...state.posts] )

尽管如此,您还应该重构您的state。函数不是状态,所以把它们放在你的状态之外。

【讨论】:

谢谢菲利克斯!我认为这部分代码有效,因为我只想在加载时获取数据库一次,问题是当我运行 createNewPost 函数时。 ups,使用了错误的功能。更新了它。问题还是一样。

以上是关于为啥当我使用 React 钩子和 React 上下文添加新帖子时,我的状态会替换我的帖子的主要内容,如果未能解决你的问题,请参考以下文章

在使用数据库数据更新上下文后,React 'useContext' 钩子不会重新渲染

为啥在 React 中使用 useImperitaveHandle 钩子?

React - 如何获取上下文中钩子的值

为啥 jest 不能为我正在测试的自定义 React 钩子提供 useTranslation 钩子?

为啥我不能将其转换为自定义的 React 钩子?

更干净的 React 上下文