状态更改后,React Native元素不会重新渲染

时间:2020-05-17 20:56:49

标签: typescript react-native redux

我一直在研究此错误已有2天了,但我似乎无法弄清楚这种错误的方式和原因。我的应用程序中有FlatList个元素,其中ProductComponent个元素,可以通过推送TouchableHighlight中定义的ProductComponent组件来买卖。
以下是我的FlatList组件及其呈现的ProductComponent的代码:

FlatList组件:

    const ProductList: React.FC = () => {
    const energyResources = useSelector((state: RootState) => state.energyResources).asImmutable();
    const dispatch = useDispatch<RootDispatch>();
    const coins = useSelector((state: RootState) => state.coins).coins;

    const purchaseItem = (item: IEnergyResource): void => {
        if (coins > item.price) {
            dispatch.energyResources.increaseAmountOwned(dispatch.energyResources, item);
            dispatch.coins.buy(dispatch.coins, item.price);

            Alert.alert(
                'Gekocht!',
                'Je hebt zojuist de energiebron ' + item.name + ' gekocht, ' +
                '\nJe hebt nu nog €' + coins + ' Euro!'
            );
        } else {
            Alert.alert(
                'Niet gekocht',
                'Sorry, je hebt niet genoeg geld om deze energiebron te kopen.'
            );
        }
    };

    const sellItem = (item: IEnergyResource): void => {
        if (item.amountOwned > 0) {
            dispatch.energyResources.decreaseAmountOwned(dispatch.energyResources, item);
            dispatch.coins.sell(dispatch.coins, item.price);

            Alert.alert(
                'Verkocht!',
                'De energiebron ' + item.name + ' is verkocht, ' +
                'je hebt nu €' + coins + ' Euro.'
            );
        }  else {
            Alert.alert(
                'Niet verkocht',
                'Sorry, de energiebron ' + item.name + ' kon niet worden verkocht, ' +
                'je hebt er geen in je bezit.'
            );
        }
    };

    return (
        <FlatList
            style={styles.list}
            data={energyResources.toArray()}
            renderItem={
                ({ item }) => <ProductComponent
                    resource={item}
                    onPurchase={purchaseItem}
                    onSell={sellItem}
                    canSell={item.amountOwned > 0}
                />
            }
            keyExtractor={(item) => item.name}
        />
    );
}

买卖方法都在FlatList组件中定义,然后传递给各个元素(我认为这比在ProductComponent自身中定义功能并让每个渲染项更好)致电状态)。

ProductComponent组件:

export interface IProductProps {
    resource: IEnergyResource;
    onPurchase: Function;
    onSell: Function;
    canSell: boolean;
}

const styles = StyleSheet.create({
    buttonRight: {
        alignItems: 'center',
        alignSelf: 'flex-end',
        backgroundColor: Constants.Colors.DodgerBlue,
        marginVertical: 5,
        padding: 10,
        width: 150
    },
    image: {
        alignSelf: 'flex-start',
        height: 100,
        width: 100
    },
    listItem: {
        borderBottomColor: Constants.Colors.Blue,
        borderBottomWidth: 2,
        flex: 1,
        flexDirection: 'row',
        marginLeft: 5,
        marginBottom: 0,
        paddingBottom: 5
    },
    productInfo: {
        width: 300,
    },
    rightButtons: {
        alignItems: 'center',
        alignSelf: 'flex-end'
    },
    sell: {
        backgroundColor: Constants.Colors.Red
    },
    textLeft: {
        alignSelf: 'flex-start',
        fontSize: 20,
    }
});

const ProductComponent: React.FC<IProductProps> = (props) => {

    return (
        <View style={styles.listItem}>
            <Image source={props.resource.image.image} width={50} height={50} style={styles.image} />
            <View style={styles.productInfo}>
                <Text style={styles.textLeft}>{props.resource.name}</Text>
                <Text style={styles.textLeft}>€{props.resource.price}</Text>
                <Text style={styles.textLeft}>Energiewaarde: {props.resource.energyValue} Watt</Text>
                <Text style={styles.textLeft}>In bezit: {props.resource.amountOwned}</Text>
            </View>
            <View style={styles.rightButtons}>
                <TouchableHighlight style={styles.buttonRight} onPress={() => props.onPurchase(props.resource)}>
                    {/* eslint-disable-next-line react-native/no-inline-styles */}
                    <Text style={{ color: Constants.Colors.White, fontWeight: 'bold', fontSize: 15 }}>Kopen</Text>
                </TouchableHighlight>
                <TouchableHighlight style={[styles.buttonRight, styles.sell]} disabled={props.canSell} onPress={() => props.onSell(props.resource)}>
                    {/* eslint-disable-next-line react-native/no-inline-styles */}
                    <Text style={{ color: Constants.Colors.White, fontWeight: 'bold', fontSize: 15 }}>Verkopen</Text>
                </TouchableHighlight>
            </View>
        </View>
    );
};

该方法存在于IProductProps界面中,并且调用似乎可以正常工作(我正在获取定义的Alert,好像我确实已经购买了产品一样)。但是,在警报框中单击 OK 后,指定产品(在ProductComponent中定义为props.resource.amountOwned的计数器仍然为0,我无法出售该产品。 / p>

这些是我在状态模型中定义的方法:

/**
 * Increases the amount of items the player owns.
 *
 * @param {List<IEnergyResource>} state - the current state of the app
 * @param {IEnergyResource} item - the item which was bought
 * @returns {List<IEnergyResource>} state
 */
function increaseAmountOwned(state: EnergyResourcesState, item: IEnergyResource): EnergyResourcesState {
    const itemIndex = state.indexOf(item);
    const newItem = {
        amountOwned: item.amountOwned++,
        ...item
    };

    return state.set(itemIndex, newItem);
}

/**
 * Decreases the amount of items the player owns.
 *
 * @param {List<IEnergyResource>} state - The current state of the app
 * @param {IEnergyResource} item - the item which was sold
 * @returns {List<IEnergyResource>} state
 */
function decreaseAmountOwned(state: EnergyResourcesState, item: IEnergyResource): EnergyResourcesState {
    const itemIndex = state.indexOf(item);
    const newItem = {
        amountOwned: item.amountOwned--,
        ...item
    } as IEnergyResource;

    return state.set(itemIndex, newItem);
}

const initialState: IEnergyResource[] =
    [
        {
            name:'Windmolen',
            price: 15,
            energyValue:20,
            environmentValue:-15,
            image:{

                maxSize:{
                    width:0.2,
                    height:0.2,
                },
                image: images.windmill,
            },
            amountOwned: 0,
            amountTotal: 30,
            amountPlaced: 0,
            location:{
                x:0.05,
                y:0
            },
        },{
            name:'Watermolen',
            price: 15,
            energyValue:15,
            environmentValue:-10,
            image:{

                maxSize:{
                    width:0.2,
                    height:0.2,
                },
                image: images.turbine
            },
            amountOwned: 0,
            amountTotal: 30,
            amountPlaced: 0,
            location:{
                x:0.05,
                y:0.3
            },
        },{
            name:'Zonnepaneel',
            price: 15,
            energyValue:10,
            environmentValue:-5,
            image:{

                maxSize:{
                    width:0.2,
                    height:0.2,
                },
                image: images.solarPanel
            },
            amountOwned: 0,
            amountTotal: 30,
            amountPlaced: 0,
            location:{
                x:0.3,
                y:0
            },
        }
    ]

const resources = {
    state: List(initialState),
    reducers: {
        place:(state: EnergyResourcesState, name: string): EnergyResourcesState =>
            state = doMutateEnergyResource(state, name, true),
        remove:(state: EnergyResourcesState, name: string): EnergyResourcesState =>
            state = doMutateEnergyResource(state, name, false),
        increaseAmountOwned: increaseAmountOwned,
        decreaseAmountOwned: decreaseAmountOwned
    },
};

我正在使用Rematch Redux framework处理该州。

这可能是我在这里忽略的一个小细节,因此非常感谢在正确方向上的任何帮助或推动。

提前谢谢!

1 个答案:

答案 0 :(得分:0)

事实证明,我误解了Rematch Reducers与该州相关的工作方式。它们应被视为对已定义状态(在这种情况下为resources的扩展方法)。从化简器的定义中可以看出,化简器有两个参数。当前状态以及要进行的任何更改。

据我了解,我需要为用户提供当前处于活动状态的状态(在本例中为FlatList),就像这样:

 dispatch.energyResources.increaseAmountOwned(dispatch.energyResources, item);

这是我的错误,因为state参数由调用该方法时在后台由Rematch提供。该方法需要这样调用:

 dispatch.energyResources.increaseAmountOwned(item);

重新匹配将注意到increaseAmountOwned()的调用,并在执行之前将dispatch.energyResources中存在的当前状态注入该方法。