1

使用

反应还原

redux-persist

还原动作

反应式

我正在自己学习 react-redux 和 react-native。我现在正在尝试从 react-redux 的列表中更新单个项目。我的项目中有很多类别和商店。用户将选择一个类别,然后单击商店列表中一项的“喜欢按钮”。这就像 instagram 或 facebook。

当我改变一个项目的状态时,商店列表中每个项目的状态都会同时改变。

我不知道为什么会这样。

我将结构设置为ducks模式以避免在更改状态时更改太多文件。如果有人提供一些建议,我将不胜感激,这可能对我有所帮助。谢谢你。我看到一些文章来解决这个问题,必须给出 id 来区分项目并将有效负载作为对象。我不太明白,所以我的代码现在很乱。但我想知道我的代码发生了什么,所以我分享了我的代码。


restaurantContainer.js

class RestaurantListContainer extends Component {
    shouldComponentUpdate(nextProps) {
        return nextProps.imgUrls !== this.props.imgUrls;
}

componentDidMount() {
    const {category, StoreActions} = this.props;

    try {
        StoreActions.fetchStoreInfo(category);
        StoreActions.fetchImgUrl(category);
        this.getUid();
    } catch (e) {
        console.log(e);
    }
}

async getUid() {
    const {StoreActions} = this.props;
    const uid = await storage.getItem('uid');
    StoreActions.fetchLikeList(uid);
}

render() {
    const {fetching, tabColor, tabName, category, categoryId, navigation, stores, imgUrls, like} = this.props;
    const {onClick} = this;

    return (
        <View>
            ...

            <ScrollView>
                {
                    fetching ?
                        <View>
                            <Bars size={30} color="#40D59B"/>
                        </View>
                        :
                        stores.map((store, i) =>
                            <View key={`item-${i}`}>
                                <RestaurantItem
                                    key={`restaurantItem-${i}`}
                                    i={i}
                                    category={category}
                                    navigation={navigation}
                                    storeInfo={store}
                                    imgUrls={imgUrls[i]}
                                    categoryId={categoryId}
                                    like={like}
                                />
                            </View>
                        )
                }
            </ScrollView>
        </View>
    );
}
}

export default connect(
({styleMod, storeMod}) => ({
    stores: storeMod.stores,
    imgUrls: storeMod.imgUrls,
    fetching: storeMod.fetching,
    likeList: storeMod.likeList
}),
(dispatch) => ({
    StoreActions: bindActionCreators(storeActions, dispatch),
})
)(RestaurantListContainer);

restaurantItem.js

class RestaurantItem extends Component {
pressFunc = (item) => {
    const {navigation} = this.props;
    const {push} = navigation;

    console.log(item.name);

    push('RestaurantDetail', {info: item});
}

voteAdder = async (storeName) => {
    const uid = await storage.getItem('uid');
    const {i, categoryId} = this.props;

    if (uid) {
        const {VoteActions, LikeActions, category, favoriteStores} = this.props;

        try {
            VoteActions.voteAdd(favoriteStores, category, storeName, uid);
            LikeActions.likeClicked(storeName, category, categoryId, i);
        } catch (e) {
            console.log(e);
        }
    } else {
        alert('You are not authorized!');
    }
}

render() {
    const {i, storeInfo, category, categoryId, imgUrls, favoriteStores, like} = this.props;

    return (
        <View style={restaurantCard}>
            <StoreImg
                img={imgUrls}
                name={storeInfo.name}
            />
            <StoreInfoBlock
                i={i}
                storeInfo={storeInfo}
                pressFunc={this.pressFunc}
            />
            <View style={{flexDirection: 'column'}} >
                {
                        <ThumbImg
                            voteAdder={() => this.voteAdder(storeInfo.name)}
                            name={storeInfo.name}
                            favoriteStore={favoriteStores[category]}
                            category={category}
                            like={like}
                            categoryId={categoryId}
                        />
                }
                <Score count={storeInfo.count}/>
            </View>
        </View>
    );
}
}


export default connect(
({voterMod, likeMod}) => ({
    favoriteStores: voterMod.favoriteStores,
    like: likeMod.like,
}),
(dispatch) => ({
    VoteActions: bindActionCreators(voteActions, dispatch),
    LikeActions: bindActionCreators(likeActions, dispatch),
})
)(RestaurantItem);

thumbImg.js

export default class ThumbImg extends Component {
onClick = () => {
    this.props.voteAdder();
}

onFlag = () => {
    const {like, categoryId, i} = this.props;
        if(like.categoryById[categoryId]) {
            if(like.storeById[i]) {
                console.log(2);
                return (
                    <FastImage
                        resizeMode={FastImage.resizeMode.cover}
                        style={{width: 50, height: 50}}
                        source={require('...')}
                    />
                );
            } else {
                return (
                    <FastImage
                        resizeMode={FastImage.resizeMode.cover}
                        style={{width: 50, height: 50}}
                        source={require('...')}
                    />
                );
            }
        } else {
            return (
                <FastImage
                    resizeMode={FastImage.resizeMode.cover}
                    style={{width: 50, height: 50}}
                    source={require('...')}
                />
            );
        }
}

render() {
    return (
        <TouchableOpacity onPress={this.onClick}>
            <View style={{paddingTop: 15, paddingRight: 15}}>
                {
                    this.onFlag()
                }
            </View>
        </TouchableOpacity>
    );
}
}

喜欢Mod.js

// Action types
const ON_LIKE = 'like/ON_LIKE';
const OFF_LIKE = 'like/OFF_LIKE';
// action creator
export const likeClicked = (store, category, categoryId, i) => (dispatch) => {
const selectedCategory = {categoryById: {}};
const categoryInfo = {
    id: categoryId,
    name: category,
};

selectedCategory.categoryById[categoryId] = categoryInfo;

const selectedStore = {storeById: {}};
const storeInfo = {
    id: i,
    name: store
}

selectedStore.storeById[i] = storeInfo;

const favorites = {
    ...selectedCategory,
    ...selectedStore
}

dispatch({type: ON_LIKE, payload: favorites});
}

const initialState = {
like: {
    categoryById: {},
    storeById: {}
}
};

// Reducer
export default handleActions({
[ON_LIKE]: (state, action) => ({...state, like: action.payload}),
[OFF_LIKE]: (state, action) => ({...state, like: action.payload}),
}, initialState);
4

0 回答 0