javascriptreactjseventsfluentui-react

How to handle an event of a child element, on a parent element?


I have a component that contains a Checkbox component from the @fluentui/react-components library, and I am using an onChange event on the Checkbox component.

const ContactText = ({ contact, contactKey, selectedContacts, setSelectedContacts }) => {

  return (
    <div>
      <img src={contactIcon} alt="Contact Icon" />
      <div>
        <Checkbox
          labelPosition="before"
          label={`${contact.firstname} ${contact.surname}`}
          checked={selectedContacts.filter((contact) => contact.key == contactKey).checked}
          //@ts-ignore - Ignore event parameter on onChange
          onChange={(event, data) => {
            setSelectedContacts((prevState: SelectedContactModel[]) =>
              data.checked
                ? [
                    ...prevState,
                    {
                      key: contactKey,
                      checked: data.checked,
                      companyKey: contact.companyKey,
                      companyName: contact.companyName,
                      individual: contact.individual,
                      title: contact.title,
                      firstname: contact.firstname,
                      surname: contact.surname,
                      telephone: contact.telephone,
                      mobile: contact.mobile,
                      retired: contact.retired,
                      address: contact.address,
                      postcode: contact.postcode,
                      email: contact.email,
                    },
                  ]
                : prevState.filter((contact) => contact.key !== contactKey)
            );
          }}
        />
        {contact.email != "" ? <SecondaryText text={contact.email} /> : <></>}
        {contact.telephone != "" ? <TertiaryText text={contact.telephone} /> : <></>}
        {contact.mobile != "" ? <TertiaryText text={contact.mobile} /> : <></>}
      </div>
    </div>
  );
};

I want to have the onChange to happen when I click the outermost div of the ContactText component. I have seen people using useRef although I am wondering if there are different ways of doing this.


Solution

  • Based on @Mike K's answer and another answer I found, this is what I came up with. This lets me call onChange from the div element outside of the Checkbox element.

    const ContactText = React.forwardRef(
      ({ contact, contactKey, selectedContacts, setSelectedContacts }: any, ref: any) => {
        const [checked, setChecked] = useState(false);
    
        React.useImperativeHandle(
          ref,
          () => {
            return {
              onChange: handleChange,
            };
          },
          []
        );
    
        // @ts-ignore: next-line - Ignore event parameter on onChange
        const handleChange = (event, data) => {
          setChecked(!checked);
    
          setSelectedContacts((prevState: SelectedContactModel[]) =>
            data.checked
              ? [
                  ...prevState,
                  {
                    key: contactKey,
                    checked: data.checked,
                    companyKey: contact.companyKey,
                    companyName: contact.companyName,
                    individual: contact.individual,
                    title: contact.title,
                    firstname: contact.firstname,
                    surname: contact.surname,
                    telephone: contact.telephone,
                    mobile: contact.mobile,
                    retired: contact.retired,
                    address: contact.address,
                    postcode: contact.postcode,
                    email: contact.email,
                  },
                ]
              : prevState.filter((contact) => contact.key !== contactKey)
          );
        };
    
        return (
          <div ref={ref}>
            <img src={contactIcon} alt="Contact Icon" />
            <div>
              <Checkbox
                labelPosition="after"
                label={`${contact.firstname} ${contact.surname}`}
                checked={selectedContacts.filter((contact: SelectedContactModel) => contact.key === contactKey).checked}
                onChange={handleChange}
              />
              {contact.email != "" ? <SecondaryText text={contact.email} /> : <></>}
              {contact.telephone != "" ? <TertiaryText text={contact.telephone} /> : <></>}
              {contact.mobile != "" ? <TertiaryText text={contact.mobile} /> : <></>}
            </div>
          </div>
        );
      }
    );