As stated in the title, I'm currently getting the following error: Cannot update a component (HomePage) while rendering a different component (Query).
I'm fairly new to React, and even though I think I know the rule I'm breaking (only use hooks at the top level to preserve the order in which they're called) I'm not sure how to achieve what I'm attempting another way.
The goal is to setPreLaunch(true) if we don't have any interviews on the backend. This code does the job, but it throws an error. I tried sending the hook as a prop to the Interviews component and handling it there, but ran into the same error.
Here is the code in question:
import React, { useState } from "react";
import Interviews from "../../components/Interviews";
import Query from "../../components/Query";
import INTERVIEWS_QUERY from "../../queries/interviews/interviews";
import {
Row,
Col,
Button,
InputGroup,
FormControl,
Form,
} from "react-bootstrap";
import Filters from "../../components/Filters";
import jsonp from "jsonp";
import queryString from "query-string";
const HomePage = () => {
const [genre, setGenre] = useState(["Any"]);
const [authorHistory, setAuthorHistory] = useState(["Any"]);
const [preLaunch, setPreLaunch] = useState(false);
const [emailEntered, setEmailEntered] = useState("");
const [emailMessage, setEmailMessage] = useState("");
if (!preLaunch) {
return (
<div>
<Row id="home-banner-container">
<Col md={12}>
{" "}
<h1 id="home-main-heading" className="text-center">
Text
</h1>
<p id="home-sub-heading" className="text-center">
Text
</p>
</Col>
</Row>
<Row>
<Col md={3}>
<Filters
genre={genre}
setGenre={setGenre}
authorHistory={authorHistory}
setAuthorHistory={setAuthorHistory}
/>
<div className="contact-blurb">
Text
</div>
<Button variant="primary" className="contact-blurb-btn">
Contact
</Button>{" "}
</Col>
<Col md={9}>
<Query query={INTERVIEWS_QUERY}>
{({ data: { interviews } }) => {
if (interviews.length < 1) {
setPreLaunch(true);
} else {
setPreLaunch(false);
}
return (
<Interviews
interviews={interviews}
genreFilter={genre}
authorHistoryFilter={authorHistory}
/>
);
}}
</Query>
</Col>
</Row>
</div>
);
} else {
return (
<div>
<Row id="home-banner-container">
<Col md={12}>
{" "}
<h1 id="home-main-heading" className="text-center">
Text
</h1>
<p id="home-sub-heading" className="text-center">
Text
</p>
</Col>
</Row>
<Row>
<Col md={{ span: 6, offset: 3 }}>
<Form
onSubmit={subscribeToNewsLetter}
className="prelaunch-email-form"
>
<InputGroup className="mb-3">
<FormControl
placeholder="Email Address"
aria-label="Email Address"
type="email"
onChange={(e) => setEmailEntered(e.target.value)}
value={emailEntered}
className="prelaunch-email-input"
/>
<InputGroup.Append>
<Button
variant="outline-secondary"
type="Submit"
className="prelaunch-email-btn"
>
Keep Me Updated
</Button>
</InputGroup.Append>
</InputGroup>
<p>{emailMessage}</p>
</Form>
</Col>
</Row>
<Row>
<Col md={3}></Col>
<Col md={9}>
<Query query={INTERVIEWS_QUERY}>
{({ data: { interviews } }) => {
if (interviews.length < 1) {
setPreLaunch(true);
} else {
setPreLaunch(false);
}
return (
<Interviews
interviews={interviews}
genreFilter={genre}
authorHistoryFilter={authorHistory}
/>
);
}}
</Query>
</Col>
</Row>
</div>
);
}
};
export default HomePage;
EDIT
Here's the updated HomePage code with the Query callback as Hero recommended.
const [genre, setGenre] = useState(["Any"]);
const [authorHistory, setAuthorHistory] = useState(["Any"]);
const [preLaunch, setPreLaunch] = useState(false);
const [emailEntered, setEmailEntered] = useState("");
const [emailMessage, setEmailMessage] = useState("");
const onInterviewsReady = (interviews) => {
setPreLaunch(interviews.length < 1);
};
const myQuery = (
<Query
query={INTERVIEWS_QUERY}
onInterviewsReady={(i) => onInterviewsReady(i)}
>
{({ data: { interviews } }) => {
return (
<Interviews
interviews={interviews}
genreFilter={genre}
authorHistoryFilter={authorHistory}
/>
);
}}
</Query>
);
...
And this is the full Query file:
import React from "react";
import { useQuery } from "@apollo/react-hooks";
const Query = ({ children, query, id, onInterviewsReady }) => {
const { data, loading, error } = useQuery(query, {
variables: { id: id },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {JSON.stringify(error)}</p>;
if (onInterviewsReady) {
onInterviewsReady(data.interviews);
}
return children({ data });
};
export default Query;
With this updated code the result is the same. A functioning website that throws the same error as before.