mobxjs / mobx-react

React bindings for MobX
https://mobx.js.org/react-integration.html
MIT License
4.85k stars 349 forks source link

Mobx Observable Not Re-Rendering On Update #802

Closed tylerolechnowicz closed 5 years ago

tylerolechnowicz commented 5 years ago

Hello,

I have been reading the documentation and searching around and for the life of me I cannot figure out why my component is not re-rendering when the value of my observable changes...

import { observable, action } from "mobx";
import { observer } from "mobx-react";
import React, { Component } from 'react';
import { FlatList, StyleSheet, View } from 'react-native';
import { ListItem, Header } from 'react-native-elements';

const listLanguages = [
    {
        id: 1,
        name: 'English'
    },
    {
        id: 2,
        name: 'Spanish'
    }
]

@observer
export default class LanguageScreen extends Component 
{
    @observable selectedLanguage = 'English'

    constructor (props) 
    {
        super(props)
    }

    @action onHandleLanguageChange(name) {
        this.selectedLanguage = name
        alert(this.selectedLanguage)
    }

    renderItem = ({ item, index }) => 
    (
        <ListItem
            key={item.id}
            title={item.name}
            bottomDivider={true}
            checkBox={{
                checked: this.selectedLanguage === item.name,
                checkedColor: '#01C6DC',
                onPress: () => this.onHandleLanguageChange(item.name)
            }}
            titleStyle={styles.text}
            onPress={() => this.onHandleLanguageChange(item.name)}        
        />
    )

    render() 
    {
        return (
            <View style={styles.container}>
                <Header
                    //barStyle="light-content"
                    leftComponent={{ 
                        icon: 'arrow-left', 
                        type: 'simple-line-icon', 
                        color: '#fff',
                        underlayColor: 'transparent',
                        onPress: () => this.props.navigation.navigate('Settings')
                    }}
                    centerComponent={{ text: 'Language', style: { color: '#fff', fontSize: 24 } }}
                    backgroundColor='#007684'
                />

                <View style={styles.listContainer}>
             <FlatList
                           scrollEnabled={false}
               keyExtractor = {i => i.id.toString()}
                           data={listLanguages}
                           renderItem={this.renderItem}
             />
        </View>
            </View>
        )
    }
}

image

When I click on the checkbox that is created in my renderItem() function, it calls onHandleLanguageChange() which does update my selectedLanguage observable, but the actual checkbox is not reflecting the change. I would appreciate any assistance.

Thanks!

danielkcz commented 5 years ago

The problem lies in FlatList which is not reactive (does not have observer). Adding @observer to ListItem should solve it. Unless you have it there already and then it's some other issue I don't see here.

mweststrate commented 5 years ago

See also: https://mobx.js.org/best/pitfalls.html#rendering-listviews-in-react-native

tylerolechnowicz commented 5 years ago

The problem lies in FlatList which is not reactive (does not have observer). Adding @observer to ListItem should solve it. Unless you have it there already and then it's some other issue I don't see here.

@FredyC image

I get a red error line when trying to add @observer to ListItem

tylerolechnowicz commented 5 years ago

See also: https://mobx.js.org/best/pitfalls.html#rendering-listviews-in-react-native

@mweststrate Thanks for your reply. I am not using an observable array in this case. The @observable that I want to cause a re-render is a boolean

danielkcz commented 5 years ago

@tylerolechnowicz Um, obviously ... You need to make a separate component with ListItem which will have the observer.

mweststrate commented 5 years ago

(@)observer is about components definitions, not about JSX (which just calls components)

So renderItem = observer(({ item, index }) => .... should do the trick.

... Or use an <Observer> section inside that inline component

tylerolechnowicz commented 5 years ago

@mweststrate Wrapping the component in worked. Thanks!

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs or questions.