【问题标题】:How to make an API call that requires info from another API call onSubmit React如何进行需要来自另一个 API 调用 onSubmit React 的信息的 API 调用
【发布时间】:2021-02-07 17:57:36
【问题描述】:

当用户输入口袋妖怪并点击提交按钮时,我有一个涉及 PokeAPI 的反应项目,我希望它从 API 中获取口袋妖怪信息以及口袋妖怪从 API 中获得的类型信息。基本上我想进行一个需要来自另一个 api 调用的数据的 api 调用,我想在提交时执行此操作。

现在我让它在提交时获得口袋妖怪信息,并在提交后在不同的组件中获得类型信息,但我这样做的方式是无限期地重新渲染组件,我戴上了创可贴修复我非常想避免的问题。

function handleSubmit(dispatch) {
  return (event) => {
    event.preventDefault();
    const pokemonNameID = new FormData(event.currentTarget).get('pokemon');
    console.log(pokemonNameID);
    api.getPokemon(pokemonNameID)
      .then((response) => {
        dispatch({
          type: 'SELECTED_POKEMON',
          payload: {
            pokemon: response.body,
          }
        })
      })
      .catch((error) => {
        console.log(error);
      });
  }
}
  return (
    <form action="" onSubmit={handleSubmit(props.dispatch)}>
      <input className="search" type="text" placeholder="name/id" name="pokemon"/>
      <input className="pkmn-button"type="submit"name="."value="."/>
    </form>
  )
}
Search.propTypes = {
  dispatch: PropTypes.func,
}

export default connect(null)(Search);
class PokemonTypes extends Component {
    shouldUpdate = true;
    count = 0;
    shouldComponentUpdate(){
        if(this.shouldUpdate){
            return true;
        }
        this.count=0;
        this.shouldUpdate = true;
        return false;
    }
    componentDidUpdate(){
        var typeOne=this.props.pokemon.get("types").get(0).get("type").get("name");
        var typeTwo=typeTwoExists(this.props.pokemon);
        var dispatch = this.props.dispatch;
        api.getType1(typeOne)
        .then((response) => {
            dispatch({
              type: 'POKEMON_TYPE1',
              payload: {
                type1: response.body,
              }
            })
          })
          .catch((error) => {
            console.log(error);
          });
        try{
            api.getType2(typeTwo)
            .then((response) => {
                dispatch({
                  type: 'POKEMON_TYPE2',
                  payload: {
                    type2: response.body,
                  }
                })
              })
              .catch((error) => {
                console.log(error);
              });
        }catch(e){
            
        }
          this.count+=1;
          if (this.count%2===0){
              this.shouldUpdate = false;
          }
    }
    render() {
        var typeOne=this.props.type1.get("name");
        //this.props.pokemon.get("types").get(0).get("type").get("name");
        var typeTwo=typeTwoExists(this.props.pokemon);
        return (
            <div>
                <IsPokemonTypes type1={typeOne}
                type2={typeTwo} />
             </div>
        )
    }
}

export default connect(mapStateToProps)(PokemonTypes);

当所有 api 调用都需要来自另一个也称为 onSubmit 的 API 调用的信息时,我该如何进行 onSubmit 调用?

【问题讨论】:

    标签: reactjs api redux


    【解决方案1】:

    如果我没看错的话,首先我们调用获取口袋妖怪,然后一旦我们得到口袋妖怪数据,我们再调用两次来获取类型?我不喜欢这两种类型是本质上相同代码的重复版本,但这不是你要问的。

    在我看来,处理第二个 API 调用的最佳方法是有条件地呈现第二个组件,该组件会启动加载类型。您将有一个父组件来处理加载 Pokemon 数据并从状态中选择它。一旦该组件看到数据以状态加载,它就会呈现类型加载组件,并传入在第一次 API 调用中设置为状态的 props。类型加载组件将在挂载后立即执行第二个 API 调用。

    编辑:

    第二个响应不依赖于第一个响应的全部,它只依赖于第一个响应中的一小部分数据(类型名称/ID)。所以我们想把它抽象成一个 Type 组件,它只接受一个 prop name

    就获取和呈现的组件与用于获取和呈现的单独组件相比,主要考虑因素是您是否希望在应用的不同页面上重用具有多种不同显示格式的相同获取逻辑。当你变得更高级时,你可能想打破它,但现在我们的组件将同时获取和渲染。

    当您向 redux 分派一个类型时,我们不希望此操作与特定的 pokemon 相关联。而不是type: 'POKEMON_TYPE1',它应该是type: 'RECEIVE_TYPE'。我们将类型存储到状态的单独部分。当您访问特定 pokemon 的类型时,您将使用 redux 选择器从 pokemon 对象中选择类型名称,然后从类型状态部分中选择类型数据。现在我考虑了一下,这实际上很容易避免重复的类型调用。我们传入类型名称(总是定义的string)和类型数据(可能是完整的响应,也可能是undefined),如果数据是undefined,我们只需要启动获取。

    顺便说一句,由于您只是在学习,我建议您使用函数组件和钩子而不是类组件和connect(mapStateToProps) 来学习。您正在使用旧方法,它仍然有效,但为什么不学习新方法呢?

    这是不完整的伪代码,需要进行更改和调整。

    class Type extends Component {
        componentDidMount() {
            if ( ! this.props.data ) {
                api.getType(this.props.name)
                    .then((response) => {
                        dispatch({
                            type: 'RECEIVE_TYPE',
                            payload: {
                                name: this.props.name,
                                data: response.body,
                            }
                        })
                    })
            } 
        }
    
        render() {
            <div>
            {this.props.data ? (
                <>{/** your render goes here */}</>
            ) : (
                <LoadingSpinner />
            )}
            </div>
        }
    }
    
    const mapStateToProps = (state, {name}) => {
        return {
            data: state.types[name],
        }
    }
    
    export default connect(mapStateToProps)(Type)
    

    name 是直接提供的常规道具。 data 来自一个选择器,它根据 name 属性查找类型数据。由于我们的组件是连接的,在从componentDidMount 发送dispatch 之后,this.props.data 应该被定义。

    PokemonTypes 组件将 pokemon 对象作为道具,通过将所有工作都交给我们的 Type 组件来减少到几乎没有。

    class PokemonTypes extends Component {
        render() {
            return (
                <div>
                    {this.props.pokemon.types.map( typeObject => (
                        <Type name={typeObject.type.name}/>
                    ) )}
                 </div>
            )
        }
    }
    

    我不知道您的自定义 pokemon 对象是如何工作的,所以 map 是基于 API 响应的数据格式。请注意,当我们将typeOnetypeTwo 作为类型数组处理时,我们不必分别处理它。如果我们想以不同的方式渲染这两种类型,我们可以将 slot 作为 prop 传递给 Type

    {this.props.pokemon.types.map(typeObject => (
        <Type
            name={typeObject.type.name}
            slot={typeObject.slot}
        />
    ))}
    

    【讨论】:

    • 是的,一旦为 pokemon 进行了 api 调用,我想立即进行另一个 api 调用以获取 pokemon 拥有的 1 或 2 种类型的信息。我对这一切有点陌生,所以让我确保我理解正确,我将 pokemon 信息传递到另一个组件中,例如 然后在 pokemonType 组件中使用 componentDidMount 制作api调用类型?或者您是说制作一个专门处理加载的新组件?
    • 第一个是我建议的 (&lt;pokemonType pokemon = {this.props.pokemon} /&gt; )。但是想想我对口袋妖怪的了解,类型的反应实际上并不取决于特定的口袋妖怪,对吧?就像“电”一样,无论是来自 Pickachu 还是 Magnemite,都是相同的响应。所以Type 组件的 prop 应该是 type name 而不是 pokemon 对象。我会用一些伪代码更新我的答案。
    • 顺便说一句,我不知道你创建的这个自定义对象的实现细节this.props.pokemon.get("types").get(0).get("type").get("name"); 我假设你这样做是为了确保属性存在,而不仅仅是直接访问它们并且可能有错误。我以前习惯这样的事情,但后来我开始使用Typescript,我再也不会回头了!
    猜你喜欢
    • 1970-01-01
    • 2021-10-20
    • 2019-06-07
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    相关资源
    最近更新 更多