簡體   English   中英

React Redux state 數組變量作為道具傳遞給子組件,無限循環或空數組

[英]React Redux state array variable pass as prop to child component, either infinite loop or empty array

I am passing Redux state variable collection as props to PokeList.js, using the useEffect hook to set state, but if I set props.collection as dependency the array map function sees the props.collection as empty array, since I tried to log out在 map function 中的 pokeData 並沒有得到任何東西,如果我刪除 props.collection 依賴,它會創建一個無限循環的情況,我可以控制台記錄 props.collection,它首先顯示一個空數組,然后是正確的數組,我該怎么做正確設置 state?

我嘗試在 PokeList.js 中進行調度,結果相同,還嘗試直接初始化 cardList = props.collection.map... 但未定義 cardList,也嘗試使用 React.memo 並將 props 設置為依賴項也不起作用

//PokeList.js
import React, { useState, useEffect } from 'react';
import Card from 'react-bootstrap/Card';
import ListGroup from 'react-bootstrap/ListGroup';

const PokeList = (props) => {
    const [cardList, setCardList] = useState();
    console.log(props.collection)

    useEffect(() => {
        var newCardList = props.collection.map(pokeData => { 
            console.log(pokeData)
            return (
                <Card key={pokeData.id} style={{ width: '18rem' }}>
                    <Card.Img variant="top" src={pokeData.sprite} />
                    <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>
            )})
        setCardList(newCardList)
    }, [props.collection])

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

export default PokeList;

//Search.js
import React, { useEffect } from 'react';
import { Container } from 'react-bootstrap';
import { useDispatch, useSelector } 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])

    const collection = useSelector(state => state.pokedex.collection);

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

export default Search;

// reducer.js
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
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);
        }
    };
};

如果我嘗試直接渲染 map 結果,什么也沒有出現, map function 仍然只得到空數組,

// PokeList.js
import React from 'react';
import Card from 'react-bootstrap/Card';
import ListGroup from 'react-bootstrap/ListGroup';
import './Pokedex.css'

const PokeList = (props) => {
    console.log('props.collection', props.collection)

    return (
        // <div className='poke-list'>
        //    {cardList}
        // </div>
        <div className='poke-list'>
            {props.collection.map(pokeData => {
                return (
                    <Card key={pokeData.id} style={{ width: "18rem" }}>
                        <Card.Img variant="top" src={pokeData.sprite} />
                        <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>
                );
            })}
        </div>
    )
}

export default PokeList;

在此處輸入圖像描述

如果我刪除 [props.collection] 依賴項,它會創建無限循環情況,但組件正在渲染在此處輸入圖像描述

這里的問題是,每次Search呈現時,都會創建collection並將其傳遞給PokeList 然后PokeList正在使用該collection (記住,每次渲染都是新的)並將其用作鈎子的依賴項。 這意味着每次Search渲染時, PokeList中的鈎子都會運行。

只需使用collection prop 來渲染PokeList中的組件樹:

const PokeList = props => {
    console.log(props.collection);

    return (
        <div>
            {props.collection.map(pokeData => {
                return (
                    <Card key={pokeData.id} style={{ width: "18rem" }}>
                        <Card.Img variant="top" src={pokeData.sprite} />
                        <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>
                );
            })}
        </div>
    );
};

原來問題出在 Acions.js Problem.all 通過更改為 for 循環並等待所有獲取解決了非空數組問題

for (var i=0; i<allUrlsData.results.length; i++) {
                const res = await fetch(allUrlsData.results[i].url)
                const resData = await res.json()
                const pokemon = new Pokemon(resData)
                collection.push(pokemon)
            }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM