我正在学习构建一个pokedex应用程序,在您输入名称并点击提交后,可以提供有关pokemon的信息。它必须经过两次调用才能获得正确的信息,第一次获得它的高度和重量,然后第二次获得它的描述(例如。"Charmander通常可以在炎热地区找到……")。下面是我的行动分类。
export const fetchPokemon = function (pokemonName) {
return function (dispatch) {
dispatch(requestPokemon(pokemonName))
const requestURL = `http://pokeapi.co/api/v2/pokemon/${pokemonName}/`
return $.ajax({
url: requestURL,
}).done(function (data) {
dispatch(receivePokemon(data))
return fetchPokemonDescription(pokemonName)
}).done(function (res) {
dispatch(receivePokemonDescription(res))
})
}
}
...
export const fetchPokemonDescription = function (pokemonName) {
return function (dispatch) {
dispatch(requestPokemonDescription(pokemonName))
const requestURL = `http://pokeapi.co/api/v2/pokemon-species/${pokemonName}/`
return $.ajax({
url: requestURL,
})
}
}
我应该有一个单独的reducer为每个调用?看看关于减速器组成的文件,我不确定是否有1个减速器vs 2个减速器会更干净。这两个调用并不依赖于彼此,但是每个不同的口袋妖怪输入都需要进行调用,并且从两个口袋妖怪返回的数据属于一个口袋妖怪,所以我认为它应该在一个减速机中处理状态的一部分。
在你的情况下我会使用1个减速器。
看看你的状态结构会很有用,但我认为你有这样的:
currentPokemon: {
name: ...
height: ...
weight: ...
description: ...
}
如果是这种情况,我会使用1个reducer,因为你只管理状态的1个分支(currentPokemon)。
减速机将切换动作:在一种情况下,它将更新高度和重量,在另一种情况下,描述:
export default function currentPokemonReducer (state = initialState, action) {
switch(action.type) {
case DATA_RECEIVED:
return {
...state,
height: action.payload.height,
weight: action.payload.weight
}
case DESCRIPTION_RECEIVED:
return {
...state,
description: action.payload
}
...
default:
return state;
}
}
您正在进行的AJAX调用应该与操作类型配对。然后您应该返回类型和有效负载,我假设基于您的代码,您打算请求响应。
//Now sure where these functional are define or what they do, but I'll assume they are selectors of some sort?
export const fetchPokemon = function (pokemonName) {
return function (dispatch) {
dispatch(requestPokemon(pokemonName))
const requestURL = `http://pokeapi.co/api/v2/pokemon/${pokemonName}/`
return $.ajax({
url: requestURL,
}).done(function (data) {
dispatch(receivePokemon(data))
return fetchPokemonDescription(pokemonName)
}).done(function (res) {
dispatch(receivePokemonDescription(res))
})
}
}
你的动作可能看起来像这样:
const data = fetchPokemon(Charmander);
//this can be defined somewhere else in your app, should not be in your actions file.
export const pokemonAction(data) {
return {
type: "GET_POKEMON_NAME",
payload: data.name
}
}
//repeat for any other call
最佳实践是让你的类型单独定义,这样它们就可以被拉到你的actions文件和reducer文件中。在很大程度上,如何构建action和reducer将取决于响应对象。
export const getPokemonReducer(state= {}, action) {
if(action.type === "GET_POKEMON_NAME") {
return {
...state,
[pokemonName]: action.payload
}
if(action.type === "GET_POKEMON_DESC") {
return {
...state,
[pokemonDesc]: action.payload
}
}
reducer可以以许多不同的方式使用,这取决于你想如何塑造你的状态。您应该考虑如何在整个应用程序中使用这些信息。上面的例子给出了一个属性,我们称之为"Pokemon",这个属性值是上述两个属性的一个对象。
例如,如果你只想拉入名称,而不想拉入this.props.pokemon.pokemonName
,那么你可能会考虑有一个单独的减速器。我还会考虑考虑axios
和redux-promise
之类的抽象,它们使异步调用在redux中更容易管理。