I built a simple reddit app with React-Redux and when I go to a post page like /posts/mlxft5 and refresh the page it says that the post is not found. I can't figure out how to fix it. Here's my code on codesandbox. here's my app.js code
function App() {
return (
<Router >
<div className="App">
<div className="App-navbar">
<SubredditsList />
</div>
<Switch>
<Route exact path="/" component={StartMessage}/>
<Route exact path="/search" component={SearchPostsList}/>
<Route exact path="/posts" component={PostsList} />
<Route path="/posts/:postId" component={PostDetailRender}/>
<Route path="/search/:postId" component={SingleSearchPostRender}/>
<Redirect to="/" />
</Switch>
</div>
</Router>
)
}
export default App`
Right now you are only requesting posts from the API when we are on the /posts
page for a subreddit. There are no requests initiated by /posts/mlxft
. We need to add an additional thunk action that can fetch and store a single post from the id.
We don't want to fetch posts that are already in Redux when we click on a single post from the list on the /posts
page. We we will use the condition
setting of the createAsyncThunk
function to conditionally cancel the fetch if the data already exists.
export const fetchSinglePost = createAsyncThunk(
"posts/fetchSingle",
async (postId) => {
const response = await fetch(
`https://api.reddit.com/api/info/?id=t3_${postId}`
);
const json = await response.json();
return json.data.children[0].data;
},
{
condition: (postId, { getState }) => {
const { posts } = getState();
if (posts.entities[postId]) {
return false;
}
}
}
);
You need to add additional cases in your reducer to handle this thunk. Note: if you use builder callback notation instead of reducer map object notation then you could combine your two "rejected" cases.
[fetchSinglePost.pending]: (state, action) => {
state.status = "loading";
},
[fetchSinglePost.fulfilled]: (state, action) => {
state.status = "succeeded";
postsAdapter.upsertOne(state, action.payload);
},
[fetchSinglePost.rejected]: (state, action) => {
state.status = "failed";
state.error = action.error.message;
}
Inside of your PostDetailRender
component you need to dispatch
the fetchSinglePost
action. It's ok to dispatch it all cases because the thunk itself will cancel the fetching.
useEffect(() => {
dispatch(fetchSinglePost(postId));
}, [dispatch, postId]);
You could potentially have a status
for each post rather than one for the whole slice. I explain how to do that in this answer.
I also made some changes so that you don't fetch the same subreddit's posts more than once.