I'm creating a new app where I want to be able to post updates to my friends. A micro-blogging site.
I want to learn how to update the app using React hooks and React's context API. I created the following provider that takes the state as the value... I want to be able to add a new post and then update the state's posts so that I don't have to fetch the database again (using firestore) I'm really trying to save myself a call to the db...
Basically, when I call createNewPost within the state, I want to be able to update the current posts section of the state: state.posts
but when I update the state after the API call is successful, my entire posts array gets replaced for some reason. Not sure what I might be doing wrong...
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;
If I had to guess I would say you have a stale enclosure of your initial empty posts
state within the updateStatePosts
function used in your state. You can use a functional state update to access the previous state to update from. Functional state updates allow you to update from the previous state, not the state the update was enqueued/enclosed in.
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>
}