title: Calling a Hook only once before the component is rendered (Meteor/React/Apollo/Graphql)
body: <p>I'm trying to create a feed of things that updates as you swipe down. My logic is that I need to fetch the required data before rendering the feed, and I will fetch new data every time I hit the <em>n</em>th element as I swipe down the page. So I thought of having a boolean state variable to detect the first render, and then I set that to false to not run the query again.</p>
  <pre><code>const Feed = (props) =&gt; {
      const [feedArray, setFeedArray] = useState([]);
      const [firstRender, setFirstRender] = useState(true);
      const FEED_QUERY = gql`
        query getFeedArray {
          getFeedArray
        }
      `;
  
      if (firstRender) {
        const { loading, error, data } = useQuery(FEED_QUERY);
        if (loading) return &lt;Loading/&gt;;
        if (error) return `Error! ${error}`;
        feedArray.push(...data.getFeedArray);
        setFirstRender(false);
      }
  
      return (
        &lt;RenderredComponent /&gt;
      );
  }
  export default withApollo(withRouter(Feed));
  </code></pre>
  <p>Clearly, this results in an error (<code>Unexpected Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.</code>) as the <code>useQuery</code> hook is only called once in the if statement.</p>
  <p>I experimented with different ways of doing this, as I require this data before my component is rendered. I tried <code>useEffect()</code> with <code>props.client.query()</code> but that wouldn't work since it allows the gql query to be run synchronously and hence only updates the DOM with the data on the second render, and I can't block the render based on the <code>loading</code> state. I can't place <code>useQuery()</code> in <code>useEffect()</code> as it throws an error as well (hook within a hook).</p>
  <p>If I place the <code>useQuery</code> hook outside the if statement, it works but is run every render, which is unnecessary extra calls. For context - renders happen often as I scroll down due to how <a href="https://github.com/oliviertassinari/react-swipeable-views" rel="nofollow noreferrer">React Swipeable Views</a> works.</p>
  <p>So to put it simply - how can I run the <code>useQuery</code> hook only once, before the component is rendered?</p>
  <p>Any help is appreciated, thank you!</p>
  <p>EDIT: Screenshots below to illustrate what's happening,</p>
  <p><a href="https://i.stack.imgur.com/J6mUz.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/J6mUz.png" alt="Pic 1" /></a>
  <a href="https://i.stack.imgur.com/0tWGk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0tWGk.png" alt="Pic 2" /></a>
  <a href="https://i.stack.imgur.com/ezsMC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ezsMC.png" alt="Pic 3" /></a></p>
  <p>The first screenshot shows when it renders, and I print the data received to the console. I hardcoded a 5-element array to be returned on repeat for this example. Then as I swipe up, the component is being re-rendered although I do NOT need to fetch more data, but it is because the <code>useQuery</code> hook is being triggered. This is just going to keep fetching more data because the component will continually be re-rendered.</p>
  <p>Also - I need to store my data in state because I will be adding to it, and there is no other way for my component to remember what was fetched the previous time.</p>
  <p>EDIT2: The accepted answer works. But I had a misconception about how <code>useQuery</code> works, I should have done some logging on the server whenever the query was called. This calls the query once and only once, despite all the DOM updates. Furthermore, it adds it to my state only once, because after the first successful render the firstRender state is set to false. Not sure if this is ideal but this is what I would've done if I thought of logging the calls on my server.</p>
  <pre><code>const Feed = (props) =&gt; {
      const [feedArray, setFeedArray] = useState([]);
      const [firstRender, setFirstRender] = useState(true);
      const FEED_QUERY = gql`
        query getFeedArray {
          getFeedArray
        }
      `;
  
      const { loading, error, data } = useQuery(FEED_QUERY);
      if (loading) return &lt;Loading/&gt;;
      if (error) return `Error! ${error}`;
      
      if (firstRender) {
        feedArray.push(...data.getFeedArray);
        setFirstRender(false);
      }
  
      return (
        &lt;RenderredComponent /&gt;
      );
  }
  export default withApollo(withRouter(Feed));
  </code></pre>