React Memo updating Parent component state

482 Views Asked by At

I have components like below

QuestionAnsPage.component(parent):

export interface FieldsDatatype {
  id: string | number;
  attributeId: string | number,
  mainQuestionFlg?: boolean;
  mainQuestionId: number | string,
  question: string;
  **values: Array<number | string>;**
  fieldType: number;
  mandatory: boolean;
  isNumber: boolean;
  pattern?: string;
  max?: string | number;
  min?: string | number;
  displayInline?: boolean;
  error?: boolean;
  message?: string;
  options: OptionsType[] | undefined | null;
  storedColumn?: string;
  storedJson?: string;
}

type Props = {
  data?: FieldsDatatype[];
  country: string;
  handleOnConfirmClick: (data: FieldsDatatype[]) => void;
  handleOnCancelClick: () => void;
  isLoading?: boolean;
  errorMessage?: Error;
  id: string | number;
}
const QuestionAnsPageComponent = (props: Props): JSX.Element => {
    const [data, setData] = useState([]);
    
    useEffect(() => {
        if (props.data) {
          setData(props.data);
        }
      }, [props.data]);
.
.
..
}

My QuestionAnswer.componet(child):

type Props = {
  data: FieldsDatatype;
  onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
  onChangeSelect?: (id: string | number, value: string | number) => void;
  onDateChange?: (fieldName: string | number, value: string) => void;
  onBlur?: (event: React.FocusEvent<HTMLInputElement | HTMLButtonElement | HTMLTextAreaElement>) => void;
  country: string;
}

   const QuestionAnswerComponent = (props: Props): JSX.Element => {
    function comparisonForRerender(prevProps: Props, nextProps: Props): boolean {
         console.log('nextProps:', nextProps.data.values, nextProps.data.id);
         console.log('prevProps:', prevProps.data.values, prevProps.data.id);
      const nextValArr = [...nextProps.data.values];
      const prevValArr = prevProps.data ? [...prevProps.data.values] : [];
      const nextValuesLen = nextValArr.length;
      const prevValuesLen = prevValArr.length;
      if (nextValArr
        && prevValArr
        && nextValuesLen > 1
        && nextProps.data.fieldType === FIELDS_TYPE.CHECKBOX) {
        return (nextValuesLen === prevValuesLen
              && JSON.stringify(prevValArr) === JSON.stringify(prevValArr));
      } else if (nextValArr
        && prevValArr
        && nextValuesLen > 0
        && prevValuesLen > 0
        && nextProps.data.id === prevProps.data.id) {
        **return (prevValArr.includes(nextValArr[0]));**
      }
      return false;
    }
    }

    export default React.memo(QuestionAnswerComponent, comparisonForRerender);

I am using this React.memo for performance improvement. I want to render my child component when "props.data.values" (type of this field is Array<string | number>) changes. for that purpose I have created comparisonForRerender function.

I am trying to compare props.data.value in function like :(prevValArr.includes(nextValArr[0]))

But this function causing some weird behavior, my parent component state get reset to old value some how(data in this case).

I am not sure but this comparison function somehow changing my parent component state. If I remove this function then it is working fine.

1

There are 1 best solutions below

0
On

Your parent component is being updated because props.data is an array. Only the pointer of the array is checked in the dependency array, of the useEffect function, you'll need to compare value of every element in the array, or choose a different a dependency variable, maybe something like the length of the array.