React component rendered with createPortal with state controlled by parents will not rerender on state change

My issue is explained on this live example : https://stackblitz.com/edit/stackblitz-starters-qcvjsz?file=src%2FApp.tsx

Basically I’m passing a list of options to a radio button list, with the state and setter to a child component rendered with createPortal, however when the options are clicked in the child the parent component updates it’s state, but not the child, so the radio never have the checked status.

I think that in order to get the modal to update, that you need to maintain state within the modal itself.

I have a running modified version of the project here. The main change is in SelectedYearModal.jsx where I added a state variable that I use for rendering within the modal and I update the local state variable on selection within the modal.

We need to create a separate state to maintain the data of the modal, this can be used to separately maintain the modal data

Apart from this please ensure that the key is unique for all sets of labels and checkboxes, also for a group of checkboxes the name field should be the same and unique when compared to other groups, this is the reason for your issues.

import React, {
  useState,
  Dispatch,
  SetStateAction,
  useEffect,
  useContext,
} from 'react';
import { ModalContext } from '../context/modalContext';
import Modal from './Modal';

interface Props {
  years: number[];
  selectedYearIdx: number;
  setSelectedYearIdx: Dispatch<SetStateAction<number>>;
}

const SelectYearModal = ({
  years,
  selectedYearIdx,
  setSelectedYearIdx,
}: Props) => {
  const { setData, data } = useContext(ModalContext);
  return (
    <Modal>
      <h4 className="H4 semibold py-8">Filter by year</h4>
      <div>
        {years.map((year, index) => {
          const yearkey = `${Math.random()}-${year}`;
          const namekey = `${Math.random()}-${year}`;
          return (
            <div key={yearkey}>
              <input
                key={yearkey}
                type="radio"
                id={yearkey}
                name={namekey}
                checked={index === data}
                onChange={() => {
                  setData(index);
                  setSelectedYearIdx(index);
                }}
                style={{ marginRight: '8px' }}
              />
              <label htmlFor={yearkey}>{year}</label>
            </div>
          );
        })}
      </div>
    </Modal>
  );
};

export default SelectYearModal;

stackblitz

Leave a Comment