2

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!

DMQuinn
  • 59
  • 5
  • Don't mind me asking but why are you even calling your API from a setTimeout? Not sure if you are doing it for some practice reason or you don't understand the useEffect's purpose, but basically inside the useEffect you should just call your api like axios.get(..).then(response => setResults(response.data)) - without any need for async/await in the hook body (even though async / await is fine) but that timeout is really awkward.. – Ognjen Mišić Mar 27 '21 at 08:41
  • It's very much that I don't understand useEffect, I'm in the early stages of learning react. I'll look into what you suggested. Thanks for your help! – DMQuinn Mar 27 '21 at 08:47
  • Ah okay, so you definitely do not need that timeout - because your state change will re-render your component, and you set your state once the axios call is finished - so you do not need to think "procedurally" but "reactively". – Ognjen Mišić Mar 27 '21 at 08:50
  • You were completely right about the timout being unnecessary, thanks again for your help Ognjen. For my purposes I've found it sufficient to push results to an array rather than setState on the individual categories. – DMQuinn Mar 27 '21 at 09:12
  • You're welcome, I've written an answer so it can help someone else in the future. Take care! – Ognjen Mišić Mar 27 '21 at 10:37

1 Answers1

0

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.

Ognjen Mišić
  • 1,219
  • 17
  • 37