0

so I started to build a new app with react native and mobx. I have a flat list component that gets his state data from the mobx store list. and when i'm adding new item to the mobx list, it won't re render the flat list view.

here is my code:

List Component:

@inject('TravelStore')
@observer
class TripsList extends Component {

constructor(props) {
    super(props);
    this.state = {
        trips_list: props.TravelStore.trips_list
    }
};

// set the navigation bar options
static navigationOptions = ({ navigation }) => {
    const { params = {} } = navigation.state;
    return {
        title: 'Your Trips',
        headerRight: (
            <Button transparent primary onPress={ params.addNewTrip }>
                <Icon name='ios-add' />
            </Button>
        )
    };
};

// connect between component functions to header
componentDidMount() {
    this.props.navigation.setParams({ 
        addNewTrip: this._addNewTrip.bind(this),
    });
}

_addNewTrip() {
    this.props.TravelStore.addNewTrip('bla')
}

_renderListItem({ item }) {
    return (
        <TripsListItem details={item} navigation={this.props.navigation}/>
    );
};

render() {
    return (
        <Container>
            <FlatList
                data = {this.state.trips_list}
                renderItem = {this._renderListItem.bind(this)}
                keyExtractor={(item, index) => index}
            />
        </Container>
    );
};
}

mobx store:

class ObservableTravelListStore {

@observable trips_list = [
    {
        name: 'to denver',
        trip_cost: 400,
        buying_list: [
            { name: 'pizza', price: 10 },
            { name: 'burger', price: 40 },
            { name: 'ipad', price: 44 },
            { name: 'bus', price: 45 },
        ]
    },
    {
        name: 'to yafo',
        trip_cost: 30,
        buying_list: [
            { name: 'na na na', price: 10 },
            { name: 'burger', price: 40 },
        ]
    },
    {
        name: 'to tel aviv',
        trip_cost: 50,
        buying_list: [
            { name: 'na na na', price: 10 },
            { name: 'no no no', price: 40 },
        ]
    },
]


@action addNewTrip (trip_data) {
    this.trips_list.push({
        name: 'newTrip',
        trip_cost: 6060,
        buying_list: [
            { name: 'na na na', price: 10 },
            { name: 'burger', price: 40 },
        ]
    })

    console.log(this.trips_list[3])
}

}

const TravelStore = new ObservableTravelListStore()
export default TravelStore

any idea why the TripsList component won't rerender when addNewTrip function is called?

2 Answers2

0

the problem is that you are not listening to the real observable but to a copy of it, you save in state in the constructor.

<FlatList
     data = {this.state.trips_list}//change this
     renderItem = {this._renderListItem.bind(this)}
     keyExtractor={(item, index) => index}
            />

<FlatList
     data = {this.props.TravelStore.trips_list}//change to this
     renderItem = {this._renderListItem.bind(this)}
     keyExtractor={(item, index) => index}
            />

the render function is like autobind of mobx and react to changes in the observable if it's a render function of an observer

if you want to react to inner changes in the items of the list, you should add an observable scheme and this should do the trick, something like this:

class TripModel {
    @observable name = ''
    @observable trip_cost = 0
    @observable buying_list = []

constructor(name, cost, buy_list){
    this.name = name
    this.trip_cost = cost
    this.buying_list = buy_list
}
/* class functions*/
}
class ObservableTravelListStore {

@observable trips_list = [
     new Trip(
            'to denver',
             400,  
             [
               { name: 'pizza', price: 10 },
               { name: 'burger', price: 40 },
               { name: 'ipad', price: 44 },
               { name: 'bus', price: 45 },
              ]
             ),
     new Trip(
            'to yafo',
             30,  
             [
                { name: 'na na na', price: 10 },
                { name: 'burger', price: 40 },
             ]
             ),
     new Trip(
            'to tel aviv',
             50,  
             [
            { name: 'na na na', price: 10 },
            { name: 'burger', price: 40 },
             ]
             )
  ]


@action addNewTrip (trip_data) {
    this.trips_list.push(new Trip(
            'newTrip',
             6060,  
             [
            { name: 'na na na', price: 10 },
            { name: 'burger', price: 40 },
             ]
             ))

}

}

const TravelStore = new ObservableTravelListStore()
export default TravelStore

this is just better planning for reactive apps, so on change to inner content of the items in the list you will react to this change

hope that helps

0

Its an old post, but I also got stuck with something similar recently. Adding extraData in Flatlist prop list helped me.

<FlatList
    data = {this.props.TravelStore.trips_list}
    renderItem = {this._renderListItem.bind(this)}
    keyExtractor={(item, index) => index}
    extraData={this.props.TravelStore.trips_list.length} // list re-renders whenever the array length changes
/>

And as @Omri pointed out, you shouldn't be storing the observable in the Component state but make changes to it directly.

bright
  • 3
  • 3