I have been trying to make a dictionary app for a challenge I saw online and it is my first attemp on using fetch api. I think I am failing to understand a core concept which gets me stuck here.
First of all, I created a useFetch hook to get all the data for the term that is searched as follows:
try {
nProgress.start();
const res = await fetch(url);
if (!res.ok) throw new Error(res.status);
const data = await res.json();
dataSetter(data);
errorSetter(false);
} catch (err) {
errorSetter(true);
} finally {
loadingSetter(false);
nProgress.done();
}
And then in my App component I created an async function to use the hook along with my states:
async function fetchData(input) {
useFetch(
`https://api.dictionaryapi.dev/api/v2/entries/en/${input}`,
(data) => {
setTerm(data[0]);
},
setLoading,
setIsError
);
}
This is how my Word component is rendered inside the App component:
{!loading && !isError && <Word data={term} darkTheme={darkTheme} />}
The word component has a child component called Definitions which I pass the data as is, however when I try to map over the data that (?) should’ve been fetched by now before the rendering happened, since I am already checking if the data is fully loaded before I even render the parent component which renders without any problems, I am receiving an error caused by data
being null
on Definitions component.
To provide more details here’s how my mapping looks like:
{data.meanings.map((meaning) => {
/* bunch of jsx here */
{meaning.definitions.map((definition) => {
<li className="marker:text-purple-600 pt-4">
{definition.definition}
</li>;
})}
</div>;
})}
———— Edit ————
Here’s my form element where I get my input.
<form className="w-full h-full" onSubmit={handleSubmit}>
<input
type="search"
placeholder="Search for word"
value={input}
onChange={handleChange}
/>
</form>
And this is how I handle input
const [queryParams, setQueryParams] = useSearchParams();
const initialInput = queryParams.get("term") ?? "hello";
const [input, setInput] = useState("");
const [isValid, setIsValid] = useState(true);
useEffect(() => {
setInput(initialInput);
fetchData(initialInput);
}, [initialInput]);
const handleChange = (e) => {
setInput(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (input.length < 1) {
setIsValid(false);
return;
}
setIsValid(true);
setQueryParams({ term: input });
};
2
Answers
Ok, I found the answer myself and posting here for future searches.
I only had to make a fallback "component" or just render nothing when data is not fetched yet on
Definitions
component.Please note that mapping is still a function that should
return
something. Add a return statement before the JSX element in the inner mapping function.Furthermore, if you want to check the rendered output, you can use
console.log
.