Okay so I have this React app with a backend built with Node and Express. I got two endpoints, getAllPosts and createPost. getAllPosts returns an array of posts and createPosts returns an object with status and message.
So in the frontend I am fetching the data in Redux actions like so:
export const getPosts = () => async ( dispatch ) => {
try {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const { data } = await axios.get( '/api/posts', config );
dispatch({
type: GET_POSTS_SUCCESS,
payload: data
});
} catch ( error ) {
console.log( error )
}
}
export const createPost = ( postData ) => async ( dispatch ) => {
try {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const { data } = await axios.post( '/api/post', postData, config );
dispatch({
type: CREATE_POST_SUCCESS,
payload: data
});
} catch ( error ) {
console.log( error )
}
}
And the reducers look like this:
export const getPostsReducer = ( state = [], action ) => {
switch ( action.type ) {
case GET_POSTS_SUCCESS:
return {
loading: false,
posts: action.payload
};
default:
return state;
}
}
export const createPostReducer = ( state = [], action ) => {
switch ( action.type ) {
case CREATE_POST_SUCCESS:
return {
loading: false,
response: action.payload
};
default:
return state;
}
}
I can successfully render all posts in the first page load but when I create a post, the newly created one is not added right away. If I check the Redux dev tools, I don't see the updated list. But only renders or dev tools show the updated list after I reload the page. .
I am dispatching getPosts in one component like so:
useEffect( () => {
dispatch( getPosts() );
}, [ dispatch ] )
and dispatching the createPost in another component's submitHandler like this:
const submitHandler = ( e ) => {
e.preventDefault();
dispatch( createPost( { post } ) );
}
I also tried putting the submitHandler in the same component where getPosts is called so that dispatching it would trigger the useEffect and call getPosts again to get the updated list. But that doesn't work either. Besides that I also tried adding the returned list from getPosts as dependency in useEffect but if I log it then there are infinite amount gets printed on the log.
What am I doing wrong here?
CodePudding user response:
I'd change the structure a bit:
in the createPost method instead of dispatching I'd just return data
export const createPost = ( postData ) => async ( dispatch ) => {
try {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const { data } = await axios.post( '/api/post', postData, config );
return data;
} catch ( error ) {
console.log( error )
}
}
and then in your code I'd
const submitHandler = ( e ) => {
e.preventDefault();
createPost({post}).then(data=>{
dispatch({type:CREATE_POST, data})
}
this should definitely work
CodePudding user response:
The problem seems to be that React doesn't know that a new post was created. You'll need to call getPosts() after createPost() has been called.
const submitHandler = (e) => {
e.preventDefault();
dispatch(createPost({ post }));
dispatch(getPosts());
}
If you want to structure your services in a more centralized, scalable way, check out my blog post on React services: https://schneider-lukas.com/blog/react-connect-rest-api. You could just as well store the posts in the Provider component to make them available to all components in the tree, or better yet create a separate Context, Provider, and Consumer for handling posts.
