0
votes

I am new to React and Redux. Learning now about hooks and got really confused. Doing a tutorial app (the teacher is using classes) which should fetch some API data from jsonplaceholder (async) and afterwards use it with redux. For now, I fail to display the fetched data on my screen.

Also at the very bottom are two of my additional questions.

My code (that is not working): ERROR: TypeError: posts.map is not a function

PostList.js

import React, { useEffect, useState } from "react";
import { fetchPosts } from "../actions";
import { useSelector } from "react-redux";

const PostList = () => {
    const [ posts, getPosts ] = useState("");
    // posts = useSelector((state) => state.posts);
    // const dispatch = useDispatch();

    useEffect(() => {
        setPosts(fetchPosts());
    }, []);

    return (
        <div className="ui relaxed divided list">
             <ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>
        </div>
    );
};

export default PostList;

action/index.js

import jsonPlaceholder from "../apis/jsonPlaceholder";

export const fetchPosts = () => async (dispatch) => {
    const response = await jsonPlaceholder.get("/posts");

    dispatch({ type: "FETCH_POSTS", payload: response.data });
};

apis/jsonPlaceholder.js

import jsonPlaceholder from "../apis/jsonPlaceholder";

export const fetchPosts = () => async (dispatch) => {
    const response = await jsonPlaceholder.get("/posts");

    dispatch({ type: "FETCH_POSTS", payload: response.data });
};

reducers/postsReducer.js

export default (state = [], action) => {
    switch (action.type) {
        case "FETCH_POSTS":
            return action.payload;
        default:
            return state;
    }
};

I got it to work (to show the posts on my screen with the following) with this:

components/PostList.js

import React, { useEffect, useState } from "react";
import { fetchPosts } from "../actions";
import axios from "axios";

const PostList = () => {
    const [ posts, setPosts ] = useState([]);

    useEffect(() => {
        axios
            .get("https://jsonplaceholder.typicode.com/posts")
            .then((response) => {
                console.log(response);
                setPosts(response.data);
            })
            .catch((err) => {
                console.log(err);
            });
    }, []);

    return (
        <div className="ui relaxed divided list">
            <ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>
        </div>
    );
};

export default PostList;

1) But I do not use any async nor await in useEffect. Is this correct?

2) Should I use a middleware (like thunk) when I use useEffect?

3) What is with redux hooks like useSelector and useDispatch, where should I use them or should I be using either react hooks or either redux hooks?


Working code (only changed the PostList.js file):

import React, { useEffect } from "react";
import { fetchPosts } from "../actions";
import { useSelector, useDispatch } from "react-redux";

const PostList = () => {
    // const [ posts, setPosts ] = useState([]);
    const posts = useSelector((state) => state.posts);
    const dispatch = useDispatch();

    useEffect(
        () => {
            dispatch(fetchPosts());
        },
        [ dispatch ]
    );

    return (
        <div className="ui relaxed divided list">
            <ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>
        </div>
    );
};

export default PostList;
1
(1) axios returns a Promise that you are chaining, no need to async/await (2) Maybe only if you are doing external asynchronous work, i.e. like a data fetch (???) and you want to store that result in your redux store (3) Hard to follow what you are asking here.Drew Reese
(1) When working with classes, there is a need for async/await, why would it be here different? (3) Sorry, would like to know, if there is need for useState if I am using useSelector?Aaron Erdwyn
(1) Is there a need? :D Seems like a (false) assumption, Promises and Promise chains work just the same (3) Not really, but this is the difference between component state and app state. It all really just depends on your app structure and component needs. If other components need access to the posts or if you care to persist them then app state is the obvious choice, but if nothing else cares about them and they are transient, then just use component state and reduce the complexity and moving parts.Drew Reese
BTW, async/await is just syntactic sugar to make asynchronous code "look" and "feel" more like regular synchronous code, using (drumroll) ...Promises. They aren't quite equivalents, but they cover much of the same functionality with slightly varying edge cases.Drew Reese

1 Answers

2
votes
  1. you are using .then for waiting for the call to end, as much as async tells the code to wait

  2. you need to use redux-thunk if you want to run this action as redux action (because the usage of async behavior, .then either async), there is no relation between useEffect which is react effect to redux-thunk that belongs to redux part of your project

  3. you need useDispatch to dispatch function from UI


 const dispatch = useDispatch()

 useEffect(() => {
    dispatch(fetchPosts());
  }, []);

and useSelector for subscribing a redux prop to the component (as mapStateToProps)


  const posts = useSelector((state) => state.posts);

if you use them both, const [ posts, getPosts ] = useState([]); unneeded