了解React-Redux容器组件和 prop

4c8rllxm  于 2023-06-06  发布在  React
关注(0)|答案(1)|浏览(152)

我正在学习React和Redux,并创建了一个Pokemon生成器应用程序来学习。我目前正在尝试为现有的口袋妖怪做一个更新表单;然而,它使我意识到我对这些组件工作方式有一个误解。
我有一个PokemonDetailContainer

import { connect } from 'react-redux'
import { requestSinglePokemon } from '../../actions/pokemon_actions'
import { pokemonDetail } from './pokemon_detail'

const mapDispatchToProps = dispatch => ({
    requestSinglePokemon: (pokemonId) => dispatch(requestSinglePokemon(pokemonId))
})

const mapStateToProps = (state) => ({
    state: state,
    loading: state.ui.loading
})

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(pokemonDetail)

连接到PokemonDetail组件的

import React, { useEffect, useState } from "react";
import { Route, Routes } from "react-router-dom";
import { useParams } from "react-router-dom";
import { selectPokemonMoveNames } from "../../reducers/selectors";
import ItemDetailContainer from '../items/item_detail_container'
import { Item } from "../items/item";
import LoadingIcon from "./loading_icon";

export function pokemonDetail (props) {
    const { pokemonId } = useParams({pokemonId})
    const items = Object.values(props.state.entities.items)
    const moves = selectPokemonMoveNames(props.state)
    const thisPokemon = props.state.entities.pokemon[pokemonId]
    const [state, setState] = useState()
    

    useEffect(() => {
        const pokemon = props.requestSinglePokemon(pokemonId);
    }, [])

    if (thisPokemon && !props.loading.detailLoading) {
        return(
            <section className="pokemon-detail">
                <Routes>
                    <Route path="/items/:itemId" element={< ItemDetailContainer />}></Route>
                </Routes>
                <ul>
                    <figure>
                        <img src={thisPokemon.imageUrl} alt={thisPokemon.name} />
                    </figure>
                    <li><h2>{thisPokemon.name}</h2></li>
                    <li>Type: {thisPokemon.pokeType}</li>
                    <li>Attack: {thisPokemon.attack}</li>
                    <li>Defense: {thisPokemon.defense}</li>
                    <li>Moves: {moves.join(', ')}</li>
                </ul>
                <section className="toys">
                    <h3>Items</h3>
                    <ul className="toy-list">  
                        {items.map(item => <Item key={item.name} itemProps={item}/>)}
                    </ul>
                </section>
            </section>
        )
    } else {
        return (
            <LoadingIcon />
        )
    }

}

现在,我认为useEffect将允许我分派我的动作-在本例中,从以下动作加载单个口袋妖怪的请求-并通过useState将其分配给状态,但如果我尝试这样做,它会给我一个无限循环(如果在useEffect内完成)或返回空。

export const receiveOnePokemon = payload => ({
    type: RECEIVE_ONE_POKEMON,
    payload
})
...
export const requestSinglePokemon = (id) => (dispatch) => {
    APIUtil.fetchPokemon(id).then(
        (payload) => (dispatch(receiveOnePokemon(payload)))
    )
}

因此,虽然一切都正常,但当进入口袋妖怪详细信息页面时,整个状态正在重新加载,同时加载了一个口袋妖怪,我不确定如何将单个口袋妖怪信息作为 prop 传递(即,没有整个状态),因为ownProps似乎不再工作。正因为如此,我不知道如何创建一个表单来更新一个口袋妖怪。如果有人能帮助我理解useEffectmapStateToProps在此上下文中的含义,那将有很大帮助!我一直觉得很迷茫

dsekswqp

dsekswqp1#

我看了一下,我想我真的可以帮助你。看起来你有一些关于useEffect,mapStateToProps的使用的问题和担忧,以及在React和Redux应用程序中更新单个口袋妖怪。让我们一步一步地解决每个问题:
使用效果和调度动作:在当前的实现中,您正在useEffect钩子中调度requestSinglePokemon操作。但是,您需要确保requestSinglePokemon操作是从操作创建者返回的,以防止无限循环。按如下方式修改代码:

useEffect(() => {
  props.requestSinglePokemon(pokemonId); // Dispatch the action directly without assigning it to a variable
}, []);

通过移除对const pokemon =...的赋值,可以确保动作被正确分派。
访问单个口袋妖怪作为 prop :要从状态访问单个口袋妖怪并将其作为 prop 传递给组件,您可以修改PokemonDetailContainer中的mapStateToProps函数:

const mapStateToProps = (state, ownProps) => {
  const pokemonId = ownProps.match.params.pokemonId;
  const pokemon = state.entities.pokemon[pokemonId];
  return {
    pokemon: pokemon,
    loading: state.ui.loading
  };
};

这里,我们从ownProps.match.params中提取pokemonId,从路由参数中获取Pokemon的具体ID。然后,我们从Redux状态中检索相应的Pokemon,并将其作为Pokemon prop 传递给您的组件。
更新单个Pokemon:要创建一个更新单个口袋妖怪的表单,您需要调度一个操作来更新Redux商店中的口袋妖怪信息。首先,创建一个更新口袋妖怪的动作创建器:

export const updatePokemon = (pokemonId, updatedData) => (dispatch) => {
  // Dispatch the action to update the Pokemon with the provided data
  APIUtil.updatePokemon(pokemonId, updatedData).then((updatedPokemon) => {
    dispatch(receiveOnePokemon(updatedPokemon));
  });
};

在你的组件中,你现在可以定义一个表单,并在提交表单时分派updatePokemon动作:

import { updatePokemon } from '../../actions/pokemon_actions';

// ...

const handleSubmit = (event) => {
  event.preventDefault();
  const updatedData = {
    name: // get the updated name from the form field,
    pokeType: // get the updated pokeType from the form field,
    // other fields to be updated
  };

  props.updatePokemon(pokemonId, updatedData);
};

// ...

<form onSubmit={handleSubmit}>
  {/* Form fields for updating the Pokemon */}
  <input type="text" name="name" defaultValue={thisPokemon.name} />
  <input type="text" name="pokeType" defaultValue={thisPokemon.pokeType} />
  
  {/* Submit button */}
  <button type="submit">Update</button>
</form>

在handleSubmit函数中,从表单字段中提取更新的数据,并使用pokemonId和updatedData作为参数分派updatePokemon操作。
请记住导入updatePokemon动作创建器并将其包含在mapDispatchToProps函数中。
通过这些更改,您应该能够获取单个口袋妖怪,显示其详细信息,并使用React和Redux应用程序中的表单更新其信息。我真的希望我能帮助你!

相关问题