0

how is it that my Redux state is updated, and can be log out in the pokelist.js file, but my state variable is not set properly, is cardList is still an empty array, how do I set the state properly? I log out the collection in the pokelist.js file, which logs out an empty array first then an array containing the elements.

// reducer.js file
import { GET_LIMIT_NAMES } from '../actions/PokedexActions';

const initialState = {
    collection: []
};

export default (state = initialState, action) => {
    switch (action.type) {
        case GET_LIMIT_NAMES:
            return {
                collection: action.data
            };
        default:
            return state;
    }
};
//===================================================================================================
// action.js file
import Pokemon from '../Pokemon';

export const GET_LIMIT_NAMES = "GET_LIMIT_NAMES";

export const getLimitNames = (limit = 100) => {
    // redux-thunk
    return async dispatch => {
        try {
            const allResponse = await fetch(`https://pokeapi.co/api/v2/pokemon/?limit=${limit}`);
            const allUrlsData = await allResponse.json();
            // console.log(allUrlsData.results);

            const collection = [];

            Promise.all(allUrlsData.results.map(urlData => {
                var pokemon;
                fetch(urlData.url).then(resp =>
                    resp.json()
                ).then(data => {
                    // console.log(data);
                    pokemon = new Pokemon(data);
                    // pokemon.log();
                    collection.push(pokemon)
                }).catch(err => {
                    console.log(err);
                })
                return collection;
            }))

            // console.log(collection)

            dispatch({
                type: GET_LIMIT_NAMES,
                data: collection
            });

        } catch (err) {
            console.log(err);
        }
    };
};
//===================================================================================================
// I want to make a list of cards from the Redux state
// pokelist.js
import React, { useState, useEffect } from 'react';
import Card from 'react-bootstrap/Card';
import ListGroup from 'react-bootstrap/ListGroup';
import { useSelector } from 'react-redux';

const PokeList = () => {
    const [cardList, setCardList] = useState();
    const collection = useSelector(state => state.pokedex.collection);

    useEffect(() => {
        console.log(collection)
        setCardList(collection.map(pokeData => 
            <Card key={pokeData.id} style={{ width: '18rem' }}>
                <Card.Img variant="top" src={pokeData.sprite + '/100px180'} />
                <Card.Body>
                    <Card.Title>{pokeData.Name}</Card.Title>
                    <ListGroup className="list-group-flush">
                        <ListGroup.Item>{'Height: ' + pokeData.height}</ListGroup.Item>
                        <ListGroup.Item>{'Weight: ' + pokeData.weight}</ListGroup.Item>
                    </ListGroup>
                </Card.Body>
            </Card>))
    }, [collection])

    return (
        <div>
            {cardList}
        </div>
    )
}

export default PokeList;
//===================================================================================================
// search.js file where i render the component and call the dispatch function
import React, { useState, useEffect } from 'react';
import { Container, Row, Col, Image, Button } from 'react-bootstrap';
import { useDispatch } from 'react-redux';

import PokeList from './pokedex/PokeList';
import * as pokedexActions from './pokedex/actions/PokedexActions';

const Search = () => {
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(pokedexActions.getLimitNames(5))
    }, [dispatch])

    return (
        <div>
            <Container>
                <h2>Search</h2>
                <PokeList />
            </Container>
        </div>
    );
}

export default Search;
impressiveHen
  • 33
  • 1
  • 6

1 Answers1

0

useState() hook is just a function call. It returns value and function pair. values is just a constant it doesn't have any property binding.

// Think of this line
const [cardList, setCardList] = useState([]);

// As these two lines
const cardList = [];
const setCardList = someFunction;

When you call setCardList your variable is not changed immediately, it doesn't have property binding. It just tells react to return new value on next render.

See my answer React Hooks state always one step behind.

In your case you can simply skip useState hook

const PokeList = () => {
    const collection = useSelector(state => state.pokedex.collection);
    const cardList = collection.map(
           pokeData => (
                <Card key={pokeData.id} style={{ width: '18rem' }}>
                    <Card.Img variant="top" src={pokeData.sprite + '/100px180'} />
                    <Card.Body>
                        <Card.Title>{pokeData.Name}</Card.Title>
                        <ListGroup className="list-group-flush">
                            <ListGroup.Item>{'Height: ' + pokeData.height}</ListGroup.Item>
                            <ListGroup.Item>{'Weight: ' + pokeData.weight}</ListGroup.Item>
                        </ListGroup>
                    </Card.Body>
                </Card>)   
  );
  return (
        <div>
            {cardList}
        </div>
    )
}

Ozan Bulut
  • 735
  • 4
  • 14
  • I was trying to explain why it doesn't work. Now I proposed solution to your problem. – Ozan Bulut Nov 17 '19 at 09:38
  • I set cardList the way you did, but the map function doesn't run at all, meaning that it still thinks collection is an empty array, which I don't understand, since I can log out collection – impressiveHen Nov 17 '19 at 18:05