【问题标题】:How to avoid data duplicate when navigate screen?导航屏幕时如何避免数据重复?
【发布时间】:2025-12-29 15:40:17
【问题描述】:

我的情况是我有两个FlatList 组件(A 和 B)。

A 是我的第一个屏幕。我使用react-navigation 将A 导航到B,B 将在headerLeft 上显示返回箭头。当我单击箭头时,它将返回 A 。但是 FlatList 数据仍然显示 B,即使它真的在 A...

我的数据来自react-redux 的 fetch API,我认为问题来自react-redux。因为我测试了一个没有react-redux 的简单测试。问题消失了。

我想使用 react-redux 创建我的项目。我尝试使用shouldComponentUpdate 喜欢

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

goBack() 到另一个组件时仍然无法解决我的问题

我 console.log 它试图找出我的道具数据发生了什么。 当我从 A 导航到 B 时。我的 console.log 将显示如下,我发现 A 组件将被渲染...

然后我点击headerLeft上的后退箭头到A。屏幕是A但数据仍然是B添加我的console.log同时为空。

我想不通。任何帮助,将不胜感激。提前致谢。

这是我的A组件文件(B与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);

这是我的 B 组件文件:

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);

这是我的 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;
  }
};

【问题讨论】:

  • 组件 B 是否使用相同的类?
  • 不,组件 B 是另一个类组件。我已经在我的问题上发布了我的 B 组件文件。
  • 函数是this.props.fetchMainMovieList(); this.props.fetchThisWeek();在 redux 中都更新同一个对象?
  • 是的,它们在不同的 switch-case 中,我根据我的问题更新了减速器文件。

标签: react-native react-redux react-navigation


【解决方案1】:

在您的 reducer 中,您已将获取的数据添加到存储中的主对象中,相反,您应该必须维护两个不同的变量来分别保存这些不同组件的数据。尝试将减速器更改为,

    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};
      }
    };

在您的组件 A 和 B 中,您应该更改您的 mapStateToProps 以从存储中的相应对象读取数据。

对于 MainActivity 组件

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

对于 ThisWeek 组件

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

【讨论】:

  • 谢谢@Rohith,我尝试了你的代码,我发现我现在可以通过不同的组件获得不同的this.props。我能再问你一件事吗?在我的switch-case MOVIELIST_THEATER。我所有的其他剧院列表都使用相同的类组件和减速器。如果我尝试你的代码,我该如何避免这个问题?提前致谢。
  • 你需要在reducer中再添加一个对象,比如'theatreList',像weeklyMovies和allMovies一样将值保存到它,然后在你的组件中访问这个对象的值
  • 感谢您的回复,对我帮助很大,谢谢!