Dariusz Legizynski
Dariusz Legizynski

Reputation: 388

Need clarification for react + react-redux hooks + middleware thunk+ fetching API

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;

Upvotes: 1

Views: 2899

Answers (1)

Hagai Harari
Hagai Harari

Reputation: 2877

  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

Upvotes: 2

Related Questions