steven
steven

Reputation: 51

How to deal with useEffect warning when using Recoil?

I've followed the Recoil docs to create the attached which works but with the following warning

Warning: Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously later calls tries to update the component. Move this work to useEffect instead

I can't see any information about this in the docs. Can someone please explain what I need to change?

Thank you!

selector and component screen shot

Code selector.js…

import { gql } from "@apollo/client";
import { atom, selector } from "recoil";
import client from "../apollo-client";

export const stateQuery = selector({
  key: "siteState",
  get: async ({ get }) => {
    const response = await client.query({
      query: gql`
        {
          siteSettings {
            siteSettings {
              contactEmail
              internationalTelephone
            }
          }
        }
      `,
    });
    return {
      contactEmail: response.data.siteSettings.siteSettings.contactEmail,
      internationalTelephone:
        response.data.siteSettings.siteSettings.internationalTelephone,
    };
  },
});

Code ExampleBlock.js…

import React, { useState, useEffect } from "react";
import { useRecoilValue } from "recoil";
import { stateQuery } from "@recoil/selector";
import tw from "twin.macro";

export default function ArticleQuoteBlock({ data: { text, name } }) {
  const { contactEmail, internationalTelephone } = useRecoilValue(stateQuery);

  return (
    <section tw="bg-white quote md:quote-md">
      <div tw="bg-pink quote-inner md:quote-inner-md">
        <h1 tw="quote-text md:quote-text-md">{contactEmail}</h1>
        <h1 tw="quote-text md:quote-text-md">{internationalTelephone}</h1>

        <h1 tw="quote-text md:quote-text-md"></h1>
        {text && (
          <p tw="quote-text md:quote-text-md indent md:indent-md">{text}</p>
        )}
        {name && <p tw="name md:name-md">{name}</p>}
      </div>
    </section>
  );
}

Upvotes: 3

Views: 2298

Answers (1)

ilketorun
ilketorun

Reputation: 434

I believe, your ExampleBlock.js tries to mount contactEmail and internationalTelephone before their values are available. You can utilize useState and useEffect hooks to solve the issue. useState can be used to trigger rendering when the data is updated. useEffect can be used to wait for component to mount. Since you have an asynchronous call, you should define an asynchronous function inside of the useEffect, then trigger it, so that you can wait for the result and update your states accordingly.

Simplest useState usage:

const [yourState, setYourState] = useState('initialValue'). Initial value can be anything i.e. int, string, array etc.

Simplest useEffect usage:

useEffect(()=> { some_func() },[some_arg]). When some_arg is empty, some_func() is triggered only once.

In your case, below code snippet might solve the issue.

export default function ArticleQuoteBlock({ data: { text, name } }) {
    const [contactEmailInfo, setContactEmailInfo] = useState();
    const [internationalTelephoneInfo, setInternationalTelephoneInfo] = useState();
    useEffect(() => {
        async function fetchData() {
            let contactEmail;
            let internationalTelephone;
            ({ contactEmail, internationalTelephone } = await useRecoilValue(stateQuery))
            setContactEmailInfo(contactEmail);
            setInternationalTelephoneInfo(internationalTelephone);
        }
        fetchData()
    }, []);

    return (
        <section tw="bg-white quote md:quote-md">
            <div tw="bg-pink quote-inner md:quote-inner-md">
                <h1 tw="quote-text md:quote-text-md">{contactEmailInfo}</h1>
                <h1 tw="quote-text md:quote-text-md">{internationalTelephoneInfo}</h1>
                <h1 tw="quote-text md:quote-text-md"></h1>
                {text && <p tw="quote-text md:quote-text-md indent md:indent-md">{text}</p>}
                {name && <p tw="name md:name-md">{name}</p>}
            </div>
        </section>
    );
}

Upvotes: 1

Related Questions