Uncaught (in promise) Error: Invalid hook call. - SPECIAL CASE - javascript

I know that hooks cannot be called from functions other than React Functional Components, this is a bit different.
I have created some utility/service type functions that need to use hooks.
// somewhere in services files...
const utilNavTo = (route) => {
const navigate = useNavigate();
...
};
// somewhere in components for screens...
const MyScreen = () => {
...
if(something){
utilNavTo('/somewhere');
}
...
};
// the main app is created with <App /> not App, so that should not be the reason of error
ReactDOM.render(<App />, document.getElementById("root"));
// also App is fully defined with routes having <MyScreen /> defined properly...
When such a function is used within a React Functional Component, I get this error:
Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
If I call the hook from the react functional component and pass it to the utility function, it works perfectly well.
Is there some way to make this work without passing the hooks as arguments?
I guess it should only fail if the utility function itself is not called from a functional component.

Issue
The issue here is that the code is calling useNavigate in a callback function, conditionally. This breaks the rules of hooks:
Don’t call Hooks inside loops, conditions, or nested functions.
Instead, always use Hooks at the top level of your React function,
before any early returns. By following this rule, you ensure that
Hooks are called in the same order each time a component renders.
Solution
Convert the utilNavTo into a custom React hook that returns a function for a component to use. The hook should be called in the function component body.
Example:
// somewhere in services files...
const useUtilNavTo = () => {
const navigate = useNavigate();
const utilNavTo = (route) => {
...
};
return utilNavTo;
};
...
// somewhere in components for screens...
const MyScreen = () => {
const utilNavTo = useUtilNavTo();
...
if(something){
utilNavTo('/somewhere');
}
...
};

Related

Errors while building app- Nextjs/Javascript

I got the below errors while building my application. Not sure why this is happening. I wrote a fetch in a sperate function and my trying to call my fetch function (that is styled as a custom react hook) in my getStaticSite props but it is not letting me. How can I bypass this problem? I don't think I'd have this problem if I just wrote the fetch directly into the getStaticSite props, but for organizational reasons I prefer to write my fetches in functions.
The Error I get:
./pages/SSG/paristimeisg.js
6:22 Error: React Hook "useFetchParisTimeISG" is called in function "getStaticProps" that is neither a React
function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". react-hooks/rules-of-hooks
useFetchParisTimeISG code below
import React from "react";
export default async function useFetchParisTimeISG() {
const response = await fetch(
`https://timeapi.io/api/Time/current/zone?timeZone=Europe/Paris`
);
const currenttimeinparis = await response.json();
return currenttimeinparis;
}
paristimeisg page code below.
import useFetchParisTimeISG from "../../hooks/SSR/ISR/useFetchParisTimeISG";
export async function getStaticProps() {
let mytime = await useFetchParisTimeISG();
return { props: { mytime }, revalidate: 60 };
}
export default function paristimeisg({ mytime }) {
console.log("This is my time", mytime);
return (
<div>
Hello
<h2>{mytime.milliSeconds}</h2>
</div>
);
}
Extra question
I get the same error listed as the above for this page, despite not having any react hooks inside non react components(unless I am missing something?).
Error I get:
./pages/SSG/timeforISG.js
5:16 Error: React Hook "useFetchParisTimeISG" is called in function "timeforISG" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". react-hooks/rules-of-hooks
Page code
import React from "react";
import useFetchParisTimeISG from "../../hooks/SSR/ISR/useFetchParisTimeISG";
export default function timeforISG() {
let mytime = useFetchParisTimeISG();
return <div>{mytime}</div>;
}
useFetchParisTimeISG code is the same as above (top of page).
Your issue is a simple one - you are incorrectly trying to use a React Hook in a non-React component (getStaticProps, which is a NextJS function).
The solution is simple:
Create a plain old JavaScript file that is not named like a Hook (e.g. parisTimeFetcher.js)
Paste in your original code (with a function name change to avoid a possible React error over the "use" syntax, and remove the React import as it is just plain JavaScript):
export default async function fetchParisTimeISG() {
const response = await fetch(
`https://timeapi.io/api/Time/current/zone?timeZone=Europe/Paris`
);
const currenttimeinparis = await response.json();
return currenttimeinparis;
}
Now, import the function into your Next page, and use this function inside getStaticProps:
import { fetchParisTimeISG } from "../../fetchers/parisTimeFetcher";
export async function getStaticProps() {
let mytime = await fetchParisTimeISG();
return { props: { mytime }, revalidate: 60 };
}
Giving your naming that is prefixed with use, React assumes that you're trying to call a hook with its manageable state outside of a component (which it will not work) thats why it throws this error.
Hooks shouldn't be called inside a regular functions as mentionned in react official Doc
You should change your naming and remove the use Prefix (You dont have to remove it from the the file name but its recommended)

I have this React Invalid Hook Call Error that I'm getting and I wanted to see if I was breaking the rules of hooks or is it something else?

I'm getting the error below.
Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See (link I couldn't add) for tips about how to debug and fix this problem.
You might have mismatching versions of React and the renderer (such as React DOM)
Here is my code. Is it breaking rules of hooks or is the issue something else?
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useData } from 'useData';
export const checkReference = ({
refId,
}) => {
const data = useData(); //useContext hook
let refData = {};
if (refId) refData = data.getReference(refId);
useEffect(() => {
console.log('INITIAL LOGIC');
if (refData.parameter){
console.log('SECONDARY LOGIC', refData);
}
}, [])
checkReference.propTypes = {
refId: PropTypes.string,
}
checkReference.defaultProps = {
refId: null,
}
}
I am calling it from another file using
checkReference('page-name');
I've got the same issue in my Next.js app. It was a cache related issue. you can try these steps.
Delete node_modules and .next folders
Run npm install or yarn
Start your project again
React hooks are intended to be used inside Functional components like:
export const CustomComponent = () => {}
export function CustomComponent() {}
They cannot be used in normal function because it won't exist inside the context of a React component. If you want to use things like useState or useEffect inside functions defined outside a component, you have to create a custom hook. That is, create a function with the use prefix (e.g. useCheckReference) and then use it like:
export const MyComponent = () => {
const reference = useCheckReference()
}
In that way React knows that that function is presumably gonna be called inside a component and the use of hooks is reliable, also is going to make some optimizations related to hooks and components life cycle.

How to programmatically navigate to other page in Next.js?

After a post request to an external API, I would like to redirect back to the homepage. I do have some knowledge with React and this is my first time using Next.js. Here is the code:
export default function New({genres}) {
const createMovie = (values) => {
console.log(values);
axios.post(`${process.env.NEXT_PUBLIC_BASE_URL}/movies`, {
title: values.title,
description: values.description,
genres: values.genres,
release_date: values.release_date,
cover_url: values.cover_url
}).then(res => {
const router = useRouter();
router.push('/');
})
}
As you can see I used router.push() but I get this error:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
What is the most efficient way to redirect to other pages in Next.js after a function and/or requests?
You need to move where you call useRouter(). You can keep router.push() where it is.
export default function New({genres}) {
const router = useRouter();
const createMovie = (values) => {...}
}
If you look at the Rules of Hooks, you can only call the hook, useRouter() in this case, at the top level.
I also had my initialization of useRouter in my function. I fixed the same bug by placing that line into my function component instead of my function and calling router.push(...) in the function itself.

Is there a way to use react-redux (useDispatch) in react using class based components? I am using useDispatch inside render function

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
Hooks are intended to be used in Functional components only. As per the Rules of hooks they can be called from
React function components.
Custom Hooks
In order to other question
Is there a way to use react-redux (useDispatch) in react using class based components?
Yes, there are ways of using react-redux inside class based components. Using connect API provided by react-redux library which will inject the action creators into the class component. Eventually accessing the required dispatch function by this.props. You can have a look here for a basic example of how it can be used.
Hope this helps.
You cannot use hooks with class components. As written in the docs, you need to create a container/wrapper component that passes the actions.
For that you have to use connect from 'react-redux' like this:
import { connect } from 'react-redux'
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(mapStateToProps (HERE NOT NEEDED; IF YOU WANT TO DISPATCH ONLY), mapDispatchToProps)(TodoList)
export default VisibleTodoList
This would pass onTodoClick to your component via props which you can just call like any prop: this.props.onTodoClick()

Correct way to unit test/mock shared export function using props from components - React

In my React project, I have a shared exported function:
//shared_functions.js
export function buildEndpoint(region, methodName) {
return (region in this.props.regionalEndpointsMap ? this.props.regionalEndpointsMap[region] : this.props.regionalEndpointsMap["default"]) + "/" + methodName;
}
that's used and imported in multiple components such as:
//SomeComponent.jsx
import { buildEndpoint } from 'src/util/shared_functions';
....
handleSubmit = async event => {
let response = await fetch(buildEndpoint(this.state.region, 'methodName'), {
....
The problem is I'm having trouble unit testing this function due to this.props.regionalEndpointsMap in the buildEndpoint function.
My question is what would be the correct way to unit test this function following best practices? Unit test it independently of any component that uses it? Test it from a component that uses it? Haven't been able to find a way to mock this.props.regionalEndpoints when trying to test the function independently, and when trying to test it from a component, the function is unrecognized:
//test.jsx
....
//props contains regionalEndpointsMap
wrapper = shallow(<SomeComponent {...props} />);
wrapper.instance().buildEndpoint('region', 'method')
//buildEndpoint is unrecognized
And as another question that may make the above a moot point, okay to try and access a property (props) in an exported function even though it's not guaranteed to have that property in a component it's used in? Or is it frowned upon? Would it be better to create a base component class with this function and make it the parent to the component classes that use it?
Sorry if these sound like dumb questions, new to React and unit testing with jest and enzyme.
To test the function independently you could mock it, something like this:
import { buildEndpoint } from 'src/util/shared_functions';
...
let result = ({
props : {regionalEndpointsMap : {default : 'd'} },
buildEndpoint : buildEndpoint
}).buildEndpoint("r", "m")
Personally though I would pass in regionalEndpointsMap to the function to avoid the need to access the this context.

Categories