-2

Here is a Codesandbox link recreating the issue: https://codesandbox.io/s/boring-nash-svcj7?file=/src/index.js

I'm having a weird issue. I have a very simple setup Apollo setup just for testing purposes. It goes like this:

function App() {
  return (
    <ApolloProvider client={client}>
      <Main />
    </ApolloProvider>
  );
}

It's just a simple ApolloProvider that provides the client to the App component. The App component just has one line.

const Main = () => {
  const [data, setData] = useState();
  setData(1);
  return <div>Test</div>;
};

Now, when I refresh my page, I get this error:

Too many re-renders. React limits the number of renders to prevent an infinite loop.

Does anyone know what's going on here?

Why can't I use a simple hook inside of my component?

Here is the full code:

import React, { useState } from "react";
import ReactDOM from "react-dom";

import ApolloClient from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
import { ApolloProvider } from "@apollo/react-hooks";

const client = new ApolloClient({
  link: new HttpLink({
    uri: "https://api.graph.cool/simple/v1/swapi"
  }),
  cache: new InMemoryCache()
});

const Main = () => {
  const [data, setData] = useState();
  setData(1);
  return <div>Test</div>;
};

function App() {
  return (
    <ApolloProvider client={client}>
      <Main />
    </ApolloProvider>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

There is an example I was following where it does work, so I'm not sure why my example isn't.

https://codesandbox.io/s/replace-previous-results-with-next-results-nuu6x?file=/src/FilmTitles.jsx:16-24

a53-416
  • 3,585
  • 6
  • 34
  • 44

2 Answers2

1

Well you cannot setState in render function of the component. And for functional components their body is the render function. In this case setData updates the state which triggers re-rendering and on each render it calls setData again in the infinite loop:

function App() {
    const [data, setData] = useState(0);
    setData(1); // this triggers re-render which is execution of App() which again calls setData(1)
}
Rostyslav
  • 2,606
  • 9
  • 17
  • It's not true. Yes, we should NEVER call `setState ` in body of functional component. But it's not the reason this case. When you call `setState` React will check if the state is really changed, if yes it re-render, if no it don't. `data` is number, so it only re-render once when data change from `0` to `1`, when `data` is `1` and you call `setData(1)` React will not re-render the component. – Tony Nguyen Jun 24 '20 at 14:20
  • You are wrong @TonyNguyen Here is the quote from the official docs **setState() will always lead to a re-render unless shouldComponentUpdate() returns false.** and the [reference to it](https://reactjs.org/docs/react-component.html#setstate) – Rostyslav Jun 24 '20 at 14:25
  • yes, but it is working on this example, so why? https://codesandbox.io/s/replace-previous-results-with-next-results-nuu6x?file=/src/FilmTitles.jsx:16-24 – a53-416 Jun 24 '20 at 14:25
  • @a53-416 because `setSkip` is called in a callback for `onClick` event and it is ok – Rostyslav Jun 24 '20 at 14:28
  • Ah, now i see where i may be going wrong. thank you – a53-416 Jun 24 '20 at 14:30
  • @Rostyslav the quote you mentioned is for class component, in functional component there is no `shouldComponentUpdate `. For functional component **If your update function returns the exact same value as the current state, the subsequent rerender will be skipped completely.** refered from here: https://reactjs.org/docs/hooks-reference.html#functional-updates – Tony Nguyen Jun 24 '20 at 14:31
  • @TonyNguyen just checkout this sandbox and see the error https://codesandbox.io/s/boring-mclaren-fck29?file=/src/App.js – Rostyslav Jun 24 '20 at 14:39
  • I checked the codesandbox and saw `setState` cause the probem, but your explaination is not true. – Tony Nguyen Jun 24 '20 at 14:42
  • @TonyNguyen so what is your expanation? :) if my explanation is wrong just convince me with yours... – Rostyslav Jun 24 '20 at 14:43
  • You can check out the link from official documents that I mentioned, I don't have answer for now. – Tony Nguyen Jun 24 '20 at 14:45
  • You can also put the `setData(1)` inside a useEffect WITHOUT dependency, why it does not get infinite re-render? (based on your explanation it should be re-rendered infinitely) – Tony Nguyen Jun 24 '20 at 14:47
  • 1
    @TonyNguyen I have checked the link and there is a statement: ***If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. Note that React may still need to render that specific component again before bailing out*** so it seems that it does render... – Rostyslav Jun 24 '20 at 14:52
  • Thanks @Rostyslav. Now it make all sense. – Tony Nguyen Jun 24 '20 at 14:57
0

It's not a good idea to setState like that, at this moment if you just want to try put setData in a useEffect and you don't get this error again

  useEffect(() => {
    setData(1);
  }, [data]);
Lorick
  • 11
  • 1