React Native+Redux多币种价格展示异常:所有卡片显示同一价格求助
解决所有加密货币卡片显示相同价格的问题
嘿,这个问题我碰到过不少次——核心原因就是你的Redux状态只存储了单个价格值,当每个卡片组件挂载时触发getCoinPrice,最后一次请求的价格会覆盖之前所有的,所以所有卡片都显示最后那个币种的价格。下面是具体的修复方案,一步步来:
1. 重构Reducer的状态结构
把原来单个price字段改成一个prices对象,用来存储每个币种对应的价格,这样就能区分不同币种的价格了:
const INITIAL_STATE = { prices: {} }; // 改为对象存储多币种价格 export default (state = INITIAL_STATE, action) => { switch (action.type) { case COIN_PRICE: return { ...state, // 用币种符号作为key,把对应价格存入对象 prices: { ...state.prices, [action.payload.symbol]: action.payload.price } }; default: return state; } };
2. 更新Action Creator,传递币种标识
原来的action只传了价格,现在需要同时传递币种符号,这样reducer才能知道这个价格对应哪个币种:
const URL = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC,ETH,XRP,BCH,EOS&tsyms=USD'; export const getCoinPrice = (symbol) => async (dispatch) => { try { const response = await axios.get(URL); const price = response.data.RAW[symbol].USD.PRICE; return dispatch({ type: COIN_PRICE, payload: { symbol, price } // 传递包含符号和价格的对象 }); } catch (error) { throw error; } };
3. 修改Card组件,获取对应币种的价格
现在组件需要从prices对象里根据当前币种的symbol获取对应的价格,而不是直接取单个price:
class Card extends Component { componentWillMount() { this.props.getCoinPrice(this.props.item.symbol); } render() { // 根据当前币种符号获取价格,没加载出来时显示占位文本 const coinPrice = this.props.prices[this.props.item.symbol] || '加载中...'; return ( <View> <Text>{coinPrice}</Text> </View> ) } } // 从Redux状态里获取prices对象,不再取单个price export default connect( state => ({ prices: state.coinPrice.prices }), { getCoinPrice } )(Card);
额外优化:一次性获取所有价格(可选)
现在每个卡片挂载都会请求一次API,有点浪费资源。你可以在FlatList所在的父组件里一次性获取所有币种的价格,存入Redux后所有卡片直接读取即可:
父组件示例:
class CoinList extends Component { componentDidMount() { this.props.getAllCoinPrices(); } render() { return ( <FlatList data={this.props.coinList} renderItem={({item}) => <Card item={item} />} keyExtractor={item => item.symbol} /> ) } } // 新增一个获取所有价格的action export const getAllCoinPrices = () => async (dispatch) => { try { const response = await axios.get(URL); const prices = {}; // 遍历所有目标币种,提取价格存入对象 ['BTC','ETH','XRP','BCH','EOS'].forEach(symbol => { prices[symbol] = response.data.RAW[symbol].USD.PRICE; }); return dispatch({ type: SET_ALL_COIN_PRICES, // 需要在reducer里新增这个action类型的处理 payload: prices }); } catch (error) { throw error; } }; // 对应的reducer新增case: case SET_ALL_COIN_PRICES: return { ...state, prices: action.payload };
这样就能避免重复请求API,性能会更好。
内容的提问来源于stack exchange,提问作者petros
相关产品推荐
相关产品推荐

