【问题标题】:React Redux state array variable pass as prop to child component, either infinite loop or empty arrayReact Redux 状态数组变量作为道具传递给子组件,无限循环或空数组
【发布时间】:2020-03-13 05:23:26
【问题描述】:

我将 Redux 状态变量集合作为道具传递给 PokeList.js, 使用 useEffect 挂钩设置状态,但如果我将 props.collection 设置为依赖项 数组映射函数将 props.collection 视为空数组,因为我试图 在 map 函数中注销 pokeData 并且什么也得不到,如果我删除 props.collection 依赖,会造成死循环的情况,我可以 console.log props.collection,它首先显示一个空数组,然后是正确的数组, 如何正确设置状态?

我尝试在 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);
        }
    };
};

如果我尝试直接渲染地图结果,什么都没有出现,地图功能 仍然只得到空数组,

// 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] 依赖项,它会创建无限循环 情况,但组件正在渲染

【问题讨论】:

  • 为什么要把它映射到useEffect中?您是否尝试仅返回该地图或将其设置为没有 useEffect 的 var?如果你这样做,它不会做任何事情,数组是空的,并且会在填充下一次渲染时完成这项工作
  • 你不需要在 PokeList 中使用 useStateuseEffect,正如 Adolfo 所说,直接渲染卡片即可

标签: javascript reactjs redux state


【解决方案1】:

这里的问题是,每次Search 渲染时,都会创建collection 并将其传递给PokeList。然后PokeList 正在使用collection(每次渲染都是新的,请记住)并将其用作挂钩的依赖项。这意味着每次Search 渲染时,PokeList 中的钩子都会运行。

只需使用collection 属性来渲染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>
    );
};

【讨论】:

  • 我试过了,但什么也没出现,map 函数仍然接收空数组,而不是更新后的数组
  • @impressiveHen 带有dispatch 的搜索钩子有点奇怪。 pokedexActions.getLimitNames(5) 到底返回了什么?
  • 嗨,我在新编辑中添加了 action.js,它返回一个我定义的类 Pokemon 对象的数组,其中包含实例 id、名称、...
  • @impressiveHen,我认为有问题。 pokedexActions.getLimitNames(5) 正在返回一个需要接收调度函数的函数。将该钩子替换为:useEffect(() =&gt; { pokedexActions.getLimitNames(5)(dispatch); }, []);,如果有帮助,请告诉我。
  • 我按照你说的替换了我在Search.js中的钩子,但它仍然是空的,github.com/impressiveHen/Pokedex这是我的repo链接,如果你想自己测试,谢谢你回答我的问题跨度>
【解决方案2】:

原来问题出在 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)
            }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-08
    • 2017-04-30
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    相关资源
    最近更新 更多