FairyQueen
FairyQueen

Reputation: 2373

Why is a change in my app state not causing a re-render in my child component?

When a cart item view is expanded all other cart item views need to be collapsed. The problem is my item view is a separate component that needs this information passed to it from the parent. When an arrow is clicked the item id is pass from the child component back to the parent component and then to the action and finally the reducer where the app state is updated. This triggers a re-render in the parent component but this does not trickle down to the child component where it is needed even though the property that got changed is being passed to the child. Does anyone know who to get this app state change to cause a re-render in the child component?

Here is my cart item view (child component). The isExpanded variable needs to get updated from the app state change in order to control which views should be expanded and collapsed.

componentWillReceiveProps(nextProps) {
    console.log('nextProps: ', nextProps)
}

render() {
    const serverUrl = getServerAddress();
    const {product} = this.props;
    const price = product.iogmodPrice ? product.iogmodPrice : product.price;
    const isExpanded = this.props.expandedViewId === product.id;
    const imageSrc = product.imageName
        ? 'https://b2b.martinsmart.com/productimages/'+ product.imageName.replace("Original", "Thumbnail")
        : serverUrl + '/b2b/resources/images/nophoto.gif';

    return (
        <View style={styles.pContainer}>
            <CartProduct
                imageName={imageSrc}
                name={product.description}
                itemNum={product.id}
                price={price}
                pack={product.pack}
                averageWeight={product.averageWeight}
                cases={product.order_count}
            />

            <TouchableOpacity style={styles.buttonContainer} onPress={() => this.props.onExpandClick(product.id)}>
                {isExpanded ? <LineIcon name="arrow-up" style={styles.arrowIcon} /> : <LineIcon name="arrow-down" style={styles.arrowIcon} />}
            </TouchableOpacity>

            {isExpanded &&
                <ExpandHeightView height={70}>
                    <View style={styles.counterContainerView}>
                        <QuantityCounter style={{width: '100%'}} product={product} />
                    </View>
                </ExpandHeightView>
            }
        </View>
    );
}

When an expand arrow is clicked the item id is passed back and sent to the action (parent view):

expandAndCollapseItems = (id) => {
    this.props.dispatch(collapseCartItemViews(id));
}

The render line of the parent component:

render() {
     const {isLoading, displayDetails, sortCasesAsc, details, items, expandedItem} = this.props.orderInfo;

Here is where the item that was click (to be expanded) gets passed in:

    <FlatList 
            data={items}
            keyExtractor={(item, index) => item.id.toString()}
            renderItem={({item}) => <CartProductItem product={item} expandedViewId={expandedItem} onExpandClick={(id) => this.expandAndCollapseItems(id)} />}
        />

The cart action function:

export function collapseCartItemViews(id) {
    return (dispatch, getState) => {
        dispatch({
            type: types.SET_EXPANDED_STATE,
            id: id
        });
    }
}

The reducer function:

    case types.SET_EXPANDED_STATE:
        const id = action.id;

        return {
            ...state,
            expandedItem: id
        }

Upvotes: 1

Views: 207

Answers (1)

223seneca
223seneca

Reputation: 1176

In the TouchableOpacity element that contains the arrow, try changing the onPress function to this:

onPress={() => this.props.onExpandClick(product.id); this.setState(this.state);}

This should trigger a re-render when it is clicked.

Upvotes: 1

Related Questions