2

I'm using React Strict Mode for a class project, and I have an issue where components will render multiple times, and nested components will render many, many times. I use routing, and this is how my components are structured so far:

  • Main component

    • Main screen component

      • Navbar component

      • Screen components (controlled through a React Router Switch)

So in this way, clicking through some screen components route you to others. However, components seem to render 2^x times, whatever x may be. I have a screen component, for example, that seemingly renders 16 times, as I have a console.log statement that prints out 16 times.

I also query my backend in each component, using Apollo GraphQL, but in most of these renders it returns undefined, with is troublesome since I need to use that query data in functions and renders for those components. I structure my code like so:

const RegionViewer = (props) => {

    const { currentRegion } = useParams();
    const { data, refetch } = useQuery(GET_REGION, {variables: {regionId: currentRegion}});
    const [addLandmark] = useMutation(mutations.ADD_LANDMARK);
    const { data: subregions } = useQuery(GET_SUBREGIONS_BY_ID, {variables: {regionId: currentRegion}})
    const { data: landmarks} = useQuery(GET_LANDMARKS, {variables: {region_id: currentRegion}});

    const [input, setInput] = useState("");
    const [target, setTarget] = useState({});

    console.log(landmarks);
    console.log(data);
    console.log(subregions);

    if (data && subregions && landmarks) {

        const region = data.getRegion;
        const numSubregions = subregions.getSubregionsById.length;

        const updateInput = async (e) => {
            const value = e.target.value;
            setTarget(e.target);
            await setInput(value);
        }

        const createLandmark = async () => {
            console.log(region.landmarks);
            if (input == "") {
                alert("Please enter a landmark.");
            }
            else {
                const {data} = await addLandmark({variables: {region_id: region._id, landmark: input}})
            }
            target.value = "";
            setInput("");
            await refetch();

        }
        return(<div>...</div>)
    }
    else return(<></>)
}

Because I query for multiple things, which return undefined multiple times (about 14 per each, and 2 defined returns), I just wrap everything in a conditional statement. I'm wondering if there is a better way around this, while still using strict mode. I tried using a lazyQuery that I invoke with useEffect, but that does not seem to help.

Jon
  • 481
  • 1
  • 6
  • 12
  • 1
    I guess the `StrictMode` is exposing unintentional side-effects in your code. Please try to update your question to include a [Minimal, Complete, and Reproducible Code Example](https://stackoverflow.com/help/minimal-reproducible-example) so we may better see all that your code is doing. See also https://stackoverflow.com/questions/61053432/react-usestate-cause-double-rendering. – Drew Reese May 14 '21 at 04:13
  • @DrewReese I updated my post with more of my code. The post you linked shed more insight on my problem, but I still don't know how to solve it without my current workaround. – Jon May 14 '21 at 04:25
  • 1
    Start by moving all console logs into a `useEffect` hook as this will yield a more accurate measure of when your component is rendered ***to the DOM*** and not simply one of the "render phase" renders for diffing purposes. These are unintentional side-effects otherwise. – Drew Reese May 14 '21 at 04:27
  • After doing that, I see that it prints out undefined once, and the query result once, for a total of two logs. So I'm assuming then these are unintentional side-effects? How would I go about fixing them, if so? – Jon May 14 '21 at 04:40
  • 1
    That doesn't seem abnormal. It's not unusual for *some* state/values/etc to be undefined on the initial render, then data is fetched and the state/value/etc is updated and the component rerenders with the fetched data. The typical solution involves conditional rendering of loading indicators or nothing until the data is fetched and ready to display. – Drew Reese May 14 '21 at 04:49
  • I see. Since I also define functions that require the fetched data and wrap everything in the condition that the data is actually fetched, would my solution be fine then? – Jon May 14 '21 at 05:06
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/232378/discussion-between-drew-reese-and-jon). – Drew Reese May 14 '21 at 05:12

0 Answers0