Reputation: 704
I've tried for the past few days now to try and figure out why I keep getting this error-
react-dom.development.js:16227 Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
useState Component
import { useState } from 'react';
async function CreateMeta() {
const { test, setTest } = useState();
}
export default CreateMeta;
Main Component
import CreateMeta from "./createmeta.js";
const Minter = (props) => {
const onPressed = async () => {
await CreateMeta();
};
return (
<>
<Button onClick={onPressed}>Test</Button>
</>
)
}
export default Minter;
Which is then called in other components -
return (
<>
<Minter />
</>
)
I've tried several suggestions but nothing works and my code seems to be correct. Im able to useState in some of my other components only if it's set in the same component.
Whenever I try calling a useState component instead of rendering in the return, I get the invalid hook error. Same happens with other "use" Hooks. What am I doing wrong?
Upvotes: 0
Views: 2091
Reputation: 294
It is what it says. You cannot invoke hooks outside of a component.
import { useState } from 'react';
async function CreateMeta() {
const { test, setTest } = useState();
}
export default CreateMeta;
You code does not show a component. Just a function...
import { useState } from 'react';
export const CreateMeta = (props) => {
const { test, setTest } = useState();
}
EDIT1:
I am doing it this way:
import React from "react";
import { useState } from "react";
import { getUser } from "./api";
export const MainMenu = (props) => {
const [user, setUser] = useState({});
function handleClick(event) {
//this would replace async
getUser(10).then((response) => {
setUser(response.data);
});
}
return (
<div>
<button onClick={handleClick}>Klick me</button>
{user && <div>{user.firstname}</div>}
</div>
);
};
API
import { axios } from "../services/api"
export const getUser = (userId) => {
return axios.get("/url",{userId : userId }); //this will returns a promise
}
Or you can await and async
import React from "react";
import { useState } from "react";
import { getUser } from "./api";
export const MainMenu = (props) => {
const [user, setUser] = useState({});
const handleClick = async (event) => {
const response = await getUser(10);
setUser(response.data);
}
return (
<div>
<button onClick={handleClick}>Klick me</button>
{user && <div>{user.firstname}</div>}
</div>
);
};
API
import { axios } from "../services/api"
export const getUser = async (userId) => {
const response = await axios.get("/url",{userId : userId }); //this will returns a promise
return response;
}
Upvotes: 0
Reputation: 76
Main issue:
React hooks can be used only inside body of rendering function (Functional Component). In your example "useState" is called inside click handler, so it will not work.
To fix this error you should move 'useState' directly into some rendering function body or into some hook.
My guess solution:
I'm not 100% sure what you need in your exact case, but may guess:
CreateMeta
to be useCreateMeta
(so it will be a hook) and don't make it async.import { useState, useCallback } from 'react';
function useCreateMeta() {
const [test, setTest] = useState(); // <-- square brackets here (array, not object)
const createMeta = useCallback(async () => {
// do whatever you need inside, e.g.:
// set state:
setTest('creating meta...');
// Do some async things:
await new Promise(resolve => setTimeout(() => {
setTest('meta created');
resolve();
}, 1000));
}, []);
return {createMeta};
}
export default useCreateMeta;
Minter
components like this:function Minter () {
// ...
const {createMeta} = useCreateMeta();
const onPressed = async () => {
await createMeta();
};
// ...
}
Example of the code see here: https://codesandbox.io/s/cool-cookies-9be20n
Upvotes: 3
Reputation: 5371
Is CreateMeta
supposed to be a React component? Components cannot be async and cannot be called (like you do in onPressed
).
It's a bit unclear to me what you are trying to do, but you should probably have your state in the Minter
component and the onPressed
callback can change the state.
Upvotes: 0
Reputation: 457
You should define useState hook like below
import { useState } from 'react';
async function CreateMeta() {
const [ test, setTest ] = useState();
}
export default CreateMeta;
and It will work.
Upvotes: 0