React functional component on change of one of prop value to empty object doesn't re-render / return its JSX
Tags: help, react, redux
Published: 2021-06-07 12:24:25

Below is how my component looks like :

import React, { useEffect } from "react";
import { connect } from "react-redux";

const createSomeStr = ( someObj, someOtherObj ) => { 
  if ( someObj.someField ) {
    // this has a whole lot of computing to create a string but 
    // for this example I am just making it simple 
    
    return someOtherObj.someField + someObj.someField;
  }
  
  return "";
};

const myFunctionalComponent = ( props ) => {

    useEffect( () => {
        // this won't get called when someOtherObj is being set to blank.
         console.log( "on change of someOtherObj" );
    }, [ someOtherObj ] );

    return ( props.arrayOfObjects.map( ( obj, index ) => {
        return ( <div key={ "mKey"+ index }>
          <div>{ obj.someField }</div>
          <div>{ createSomeStr( obj, props.someOtherObj ) }</div>
        </div> )
  })
};

export default connect( {
  arrayOfObjects: state.someReducer.arrayOfObjects,
  someOtherObj: state.someReducer.someOtherObj
}, {} )( myFunctionalComponent );


// my reducer looks something like this ( it works fine as expected as I can make that out from redux dev tools )
export default function ( state = { someOtherObj }, action ) {
  let newSomeOtherObj = {};
  
  if ( action.type === "SOME_TYPE" ) {

newSomeOtherObj = state.someOtherObj;

delete newSomeOtherObj[ action.payload ];
  }
  
  switch( action.type ) {
  
case "SOME_TYPE":
  return {
    ...state,
    someOtherObj: newSomeOtherObj
  };
  
  default:
    return state;
  }
};

In a functional component I have used two props one as arrayOfObjects and other is an someOtherObj.

What happens is :: arrayOfObjects get its values on mount, component re-renders with desired results;

someOtherObj get its object updated with a key on some event, component re-renders with the updated string in the second div;

someOtherObj get its value updated with a blank object ( verified from redux dev tools ), component doesn't re-render until arrayOfObject gets updated. No clue why it's not re-rendering on second update of someOtherObj ...

Update1 :: You can find my useEffect and it's comment ... As per me react isn't considering it to be an update event when someOtherObj is being set to blank. I am not getting the reason for such behavior ...

Update2 :: I did convert the same component using class and the same behavior remains. Can anyone let me know it is how react behaves in such scenarios ? Like for any of the prop object changes to blank object and react doesn't consider it to be an prop update and doesn't gets into update life cycle phase ?

update3 :: I found a solution to this as to keep a field set for the lifetime of the component.

So I made these changes to the reducer ...

export default function ( state = { someOtherObj }, action ) {
  let newSomeOtherObj = { isAnyFieldPresent: false };
  
  if ( action.type === "SOME_TYPE" ) {

newSomeOtherObj = {
 ...newSomeOtherObj,
 ...state.someOtherObj
};

delete newSomeOtherObj[ action.payload ];
  }
  
  switch( action.type ) {
  
case "SOME_TYPE":
  return {
    ...state,
    someOtherObj: newSomeOtherObj
  };
  
  default:
    return state;
  }
};

Doing this the component is now able to detect all the update to someOtherObj as it never finds that object to be empty.

But this seems to be a workaround.

Yet I would Like know why such behavior ? A change is a change being it converting an object to a blank object or just changing the field values of the object and if the component is to detect changes to that object and is to fire update life cycle phase then it should on both scenarios.

let me know if I am wrong with my understanding or any thing to this issue.

Thanks and regards, Tanmay.