Home > Net >  react native FlatList not rerendering when data prop changes
react native FlatList not rerendering when data prop changes

Time:01-02

I have a FlatList component that uses Redux (indirectly) as the source for the data prop. See below

 const mapStateToProps = state => ({
   rdx_activeUsers: state.profile.activeUsers,
 });
        
 convertRdxActiveUsersObjectToUsableArray = () => {
   let activeUsersArray = [];
   Object.values(this.props.rdx_activeUsers).forEach(userObj => {
       activeUsersArray.push(userObj);
   });
   return activeUsersArray;
 };
 //-----------------------------------------------------------------------
 render() {
    let usableArray4FlatList = this.convertRdxActiveUsersObjectToUsableArray();
    
    return (
      <View>
        <FlatList
          data={usableArray4FlatList}

Whenever an active user is added or removed in Firebase DB, I have listeners that increase or reduce the size of the Redux object rdx_activeUsers.......the goal is that this change in Redux should trigger the render() function (due to Redux being used in the convertRdxActiveUsersToUsableArray function....which is present in the render() function).

I can see via debugging tool that Redux rdx_activeUsers object is updating correctly whenever I add or remove a user....however the FlatList only rerenders dynamically when I add a user (i.e. the Redux object rdx_activeUsers increases in size)...but not when I remove one (i.e the Redux object rdx_activeUsers decreases in size).

I also tried adding prop extraData={this.props.rdx_activeUsers} ...but this didnt make any difference

UPDATE AS OF 12/31 Below are my reducers......
case ACTIVE_USER_CHILD_ADDED is successfully updating Redux AND triggering the rerender
case ACTIVE_USER_CHILD_REMOVED is successfully updating Redux BUT NOT triggering the rerender....looks like thats where the issue is

case ACTIVE_USER_CHILD_ADDED:
  const key2Add = action.payload.userId;
  const val2Add = action.payload;

  return { ...state, activeUsers: { ...state.activeUsers, [key2Add]: val2Add } };


case ACTIVE_USER_CHILD_CHANGED:
  const key2Updel = action.payload.userId;
  const val2Updel = action.payload;

   if (val2Updel.active) {
        return { ...state, activeUsers: { ...state.activeUsers,[key2Updel]: val2Updel } };
    }
  
  if (state.activeUsers) {
    const updatedstate = state;
    delete updatedstate.activeUsers[key2Updel];
    return {...updatedstate};
  }
  //else
  return state;

case ACTIVE_USER_CHILD_REMOVED:
  const key2Del = action.payload.userId;
  const oldState = state;
  delete oldState.activeMsgUsers[key2Del];
  return {...oldState};

Below shows my action creators

export const _actActiveUserChildAdded = userObj => {
  return {
    type: ACTIVE_USER_CHILD_ADDED,
    payload: userObj,
  };
};

export const _actActiveUserChildChanged = userObj => {
  return {
    type: ACTIVE_USER_CHILD_CHANGED,
    payload: userObj,
  };
};

export const _actActiveUserChildRemoved = userObj => {
  return {
    type: ACTIVE_USER_CHILD_REMOVED,
    payload: userObj,
  };
};

CodePudding user response:

try this

const mapStateToProps = state => ({
   rdx_activeUsers: state.profile.activeUsers,
 });
        

 //-----------------------------------------------------------------------
 render() {
    let activeUsersArray = [];
   Object.values(this.props.rdx_activeUsers).forEach(userObj => {
       activeUsersArray.push(userObj);
   });
    
    return (
      <View>
        <FlatList
          data={activeUsersArray}

CodePudding user response:

This piece of code does not trigger a rerender

case ACTIVE_USER_CHILD_REMOVED:
  const key2Del = action.payload.userId;
  const oldState = state;
  delete oldState.activeMsgUsers[key2Del];
  return {...oldState};

By returning {...oldState} all the references inside this.state stay the same, and no update is triggered

fast solution

Put return {...oldState, activeMsgUsers: {...activeMsgUsers}} instead

better solution

Don't use delete, use Array.filter instead to create a new object reference

best solution

Refactor your conponent to hooks and make activeMsgUsers a standalone state, if you do it correctly, calling setActiveMsgUsers returning the destructured old state you cannot have that problem

CodePudding user response:

change case ACTIVE_USER_CHILD_REMOVED like following it should work, you tried modifying the object which was mutating the state object instead of returning a new object.

case ACTIVE_USER_CHILD_REMOVED:
  const key2Del = action.payload.userId;
  const {activeUsers:{[key2Del]:_,...restActiveUsers}} = state;
  return {...state,activeUsers:{...restActiveUsers}};
  • Related