让我们说react
使用redux
redux-thunk
中间件
我从外部API获取了一副牌,所以我的动作创建者看起来像这样:
const fetchDeck = {
return dispatch => {
return fetch(https://some.api.with.cards/)
.then(r => r.json())
.then(data => dispatch({type:"FETCH_DECK", deck: data}))
}
}
相应的减速器是:
const deck = (state=[], action) => {
switch(action.type) {
case "FETCH_DECK":
return action.deck
default:
return state
}
}
来自API的响应是一组卡对象,如下所示:
{
name: "ACE",
suit: "CLUBS"
}
所以现在我想向商店添加hand
道具。 hand
是一个数组,其中包含已经在玩家手中的牌,所以我创建了一个动作,允许从deck
到hand
的牌:
const drawCard = (deck, numberOfCards) => {
return {
type: "DRAW_CARD",
deck
}
}
这是相应的减速器:
const hand = (state=[], action) {
switch(action.type) {
case "DRAW_CARD":
return [...state.slice(0,action.deck)
default:
return state
}
}
最后,我尝试在<Hand>
组件中实现此行为:
class Hand extends React.component {
componentDidMount() {
const { deck, drawCards } = this.props;
drawCards(deck, 5)
}
}
但它不起作用! componentDidMount()
发生时,API请求未完成。我想到的唯一能解决问题的是:
componentDidUpdate(prevProps) {
if (prevProps.deck.length > 0) {
const { deck, drawCard } = this.props;
drawCard(deck, 5)
}
}
这是有效的,但我有一种尴尬的感觉,这不是正确的方法。此外,如果以这种方式应用,有必要使用更多的条件来防止意外行为。
有没有更好的方法来处理我的问题?
答案 0 :(得分:2)
我认为问题在于方法。而不是在一个地方初始化套牌并交给另一个地方(componentDidMount
) - 您可以创建init
动作,该动作在根组件componentDidMount
上调用。
可能看起来像这样:
function init() {
return (dispatch, getState) => {
dispatch(fetchDeck()).then(() => dispatch(drawCard(getState().deck, 5)))
}
}
答案 1 :(得分:0)
首先,您必须在使用之前验证甲板是否已被取出,Array.isArray(deck) && drawCard()
之类的东西会更安全。其次,检测到新道具到达的正确位置是componentWillReciveProps()
,如果获取了甲板,则可以安全地调用drawCard()
。