【问题标题】: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 帮助我指出了正确的方向......

标签: javascript reactjs react-hooks react-context


【解决方案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,使用了错误的功能。更新了它。问题还是一样。
    猜你喜欢
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    • 2013-12-03
    • 2022-11-30
    相关资源
    最近更新 更多