Search code examples
javascriptreactjsstatewikipedia-api

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


I'm trying to divide results into categories from a search using Wikipedia API.

Here is my Search component:

function Search() {
    const [value, setValue] = useState("");
    const [results, setResults] = useState([]);

    useEffect(() => {
        let timerId = null;
        if (value) {
            timerId = setTimeout(async () => {
                const { data } = await axios.get(
                    "https://en.wikipedia.org/w/api.php",
                    {
                        params: {
                            action: "query",
                            list: "search",
                            origin: "*",
                            format: "json",
                            srsearch: value,
                        },
                    }
                );
                console.log(data);
                setResults(data.query.search);
            }, 400  );
        }
        return () => {
            clearTimeout(timerId);
        };
    }, [value]);
    return (
        <>
            <form className="ui form">
                <input
                    type="text"
                    placeholder="Search Wikipedia..."
                    value={value}
                    onChange={(e) => setValue(e.target.value)}
                ></input>
            </form>
            <List results={results} />
        </>
    );
}

There is a sort of incremental search which explains the setTimeout.

Here is my List component:

const List = ({ results }) => {
    const [category, setCategory] = useState("");

    const renderedList = results.map((item) => {
        if (item.snippet.includes("film") || item.snippet.includes("movie")) {
            console.log("movie", item);
        }
        if (
            item.snippet.includes("band") ||
            item.snippet.includes("musician")
        ) {
            setCategory("music");
        }
        return (
            <div className="ui segment">
                <h2>
                    <a
                        href={"https://en.wikipedia.org?curid=" + item.pageid}
                        className="header"
                        target="_blank"
                        rel="noopener noreferrer"
                    >
                        {item.title}
                    </a>
                </h2>
                <p dangerouslySetInnerHTML={{ __html: item.snippet }}></p>
                <p>{category}</p>
            </div>
        );
    });

I have tried to set the Timeout to be much higher so that there isn't any active re-rendering until the full search term is typed but this gets the same result. The API only returns an array of 10 results too, so it's not dealing with a huge amount of data.

App.js only really contains List so I don't see why there would be any problems there.

Any help appreciated - thanks in advance!


Solution

  • So as we discussed in the comments and you mentioned you are a beginner with React, it's unnecessary calling axios with a set timeout because axios returns a promise, and then once the promise is resolved, you update your state, and updating your state will re-render your component.