Morton
Morton

Reputation: 5782

How to avoid data duplicate when navigate screen?

My situation is i have two FlatList component (A and B).

A is my first screen. I use react-navigation to navigate A to B , B will show back arrow on headerLeft. When i click the arrow it will back to A . But the FlatList data is still show B even it is really in A...

My data is from fetch API by react-redux, i think the problem is come from react-redux. Because i test a simple test without react-redux. The problem is gone.

I want to use react-redux create my project. I try to use shouldComponentUpdate like

shouldComponentUpdate = (nextProps, nextState) => {
    if (nextProps.movieList === this.props.movieList) {
      return false;
    }
    return true;
  };

It is still can't fix my problem when goBack() to another component

I console.log it try to find what is going on with my props data. When i navigate to B from A. My console.log will show like this, i find A component will be rendered... enter image description here

Then i click the back arrow on headerLeft to A. The screen is A but the data is still B add my console.log is empty at the same time.

I can't figure it out. Any help would be appreciated. Thanks in advance.

Here is my A component file (B is similar with A):

import React, { Component } from 'react';
import { 
  View, FlatList, Dimensions, 
  TouchableOpacity, Image,
  ActivityIndicator, Alert, Platform
} from 'react-native';
import { Icon } from 'react-native-elements';
import { connect } from 'react-redux';
import { fetchMainMovieList } from '../actions';

const { width, height } = Dimensions.get('window');
const equalWidth = (width / 2);

class MainActivity extends Component {
  static navigationOptions = ({ navigation }) => ({
    title: 'MainActivity',
    headerLeft: 
      <TouchableOpacity style={{ marginLeft: 10 }} onPress={() => navigation.navigate('DrawerOpen')} >
        <Icon name='menu' />
      </TouchableOpacity>
  });

  componentWillMount() {
    this.props.fetchMainMovieList();
  }

  renderItem({ item }) {
    return (
      <View>
        <Image 
          source={{ uri: item.photoHref }} 
          style={{ height: 220, width: equalWidth }} 
          resizeMode="cover" 
        />
      </View>
    );
  }

  render() {
    const movieData = this.props.movieList.movie;
    console.log('A component this.props=>');
    console.log(this.props);
    if (movieData === []) {
      return (
        <View style={styles.loadingStyle}>
          <ActivityIndicator />
        </View>
      );
    }
    return (
      <View style={{ flex: 1 }}>
        <FlatList
          data={movieData}
          renderItem={this.renderItem} 
          numColumns={2}
          horizontal={false}
          keyExtractor={(item, index) => index} 
        />
      </View>
    );
  }
}

const styles = {
  loadingStyle: {
    flex: 1, 
    flexDirection: 'column', 
    justifyContent: 'center', 
    alignItems: 'center'
  }
};

const mapStateToProps = (state) => {
  const movieList = state.movieList;

  return { movieList };
};

export default connect(mapStateToProps, { fetchMainMovieList })(MainActivity);

Here is my B component file:

import React, { Component } from 'react';
import { 
  View, FlatList, Dimensions, 
  Image, ActivityIndicator, Text
} from 'react-native';
import { connect } from 'react-redux';
import { fetchThisWeek } from '../actions';

const { width, height } = Dimensions.get('window');
const equalWidth = (width / 2);

class ThisWeek extends Component {
  static navigationOptions = ({ navigation }) => ({
    title: 'ThisWeek',
  });

  componentWillMount() {
    this.props.fetchThisWeek();
  }

  renderItem({ item }) {
    return (
      <View>
        <Image 
          source={{ uri: item.photoHref }} 
          style={{ height: 500, width: '100%' }} 
          resizeMode="cover" 
        />
      </View>
    );
  }

  render() {
    const movieData = this.props.movieList.movie;
    console.log('B component this.props=>');
    console.log(this.props);
    if (movieData === []) {
      return (
        <View style={styles.loadingStyle}>
          <ActivityIndicator />
        </View>
      );
    }
    return (
      <View style={{ flex: 1 }}>
        <FlatList
          data={movieData}
          renderItem={this.renderItem} 
          numColumns={1}
          horizontal={false}
          keyExtractor={(item, index) => index} 
        />
      </View>
    );
  }
}

const styles = {
  loadingStyle: {
    flex: 1, 
    flexDirection: 'column', 
    justifyContent: 'center', 
    alignItems: 'center'
  }
};

const mapStateToProps = (state) => {
  const movieList = state.movieList;

  return { movieList };
};

export default connect(mapStateToProps, { fetchThisWeek })(ThisWeek);

Here is my MyListReducer.js:

import { 
  MOVIELIST_MAINACTIVITY,
  MOVIELIST_THISWEEK,
  MOVIELIST_THEATER
} from '../actions/types';

const INITIAL_STATE = {};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {   
    case MOVIELIST_MAINACTIVITY:
      return action.payload;

    case MOVIELIST_THISWEEK:
      return action.payload;

    case MOVIELIST_THEATER:
      console.log(action.payload);
      return action.payload;

    default:
      return state;
  }
};

Upvotes: 0

Views: 880

Answers (1)

Rohith Murali
Rohith Murali

Reputation: 5669

In your reducer you have added the fetched data into the main object in store, instead, you should have to maintain two different variables to save data of those different components separately. Try by changing the reducer as,

    import { 
      MOVIELIST_MAINACTIVITY,
      MOVIELIST_THISWEEK,
      MOVIELIST_THEATER
    } from '../actions/types';

    const INITIAL_STATE = {
      weeklyMovies:[],
      allMovies:[]
    };

    export default (state = INITIAL_STATE, action) => {
      switch (action.type) {   
        case MOVIELIST_MAINACTIVITY:
          return {
            ...state,
            allMovies:action.payload
         };

        case MOVIELIST_THISWEEK:
        return {
          ...state,
          weeklyMovies:action.payload
        };          

        case MOVIELIST_THEATER:
          console.log(action.payload);
          return action.payload;

        default:
          return {...state};
      }
    };

And in your component A and B you should change your mapStateToProps to read data from corresponding objects in store.

For MainActivity component

const mapStateToProps = (state) => {
  const movieList = state.allMovies;
  return { movieList };
};

and for ThisWeek component

const mapStateToProps = (state) => {
  const movieList = state.weeklyMovies;
  return { movieList };
};

Upvotes: 1

Related Questions