Can I use hooks inside a function (not a functional component) - javascript

Here is where I would like to use my hook so that I can change one state during the run of the app.
export const simpleFunction = () => (state) => {
// here is the hook
}
I know react hooks should be used in functional components, but what about the case stated above.

Yes you can! Those functions are then called custom hooks. But it is required to use those custom hooks inside of a functional component. So technically it is now a function using hooks outside of a react component, but they still need to be bound to a component later.
Building your own Hooks lets you extract component logic into reusable functions.
Docs: https://reactjs.org/docs/hooks-custom.html
Example from the docs
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
Because your descriptions is so short I don't know if this is what you are looking for. Hope I could help :)

Related

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.

Is there a correct way to place React Hooks inside functional component?

So what im asking is there some kind of style guide for writing react functional components with hooks. Sometimes I work with components which includes different kind of hooks:
Simple React hooks like: useMemo, useCallback, ...
Project custom React hooks like: useCategory, useProducts, ...
Third-party React hooks like: useRouter, useMediaQuery, ...
Example (this is not my real code example, just for understanding):
import React, { useMemo, useEffect, useCallback } from "react";
import { useRouter } from "next/router";
import { useMediaQuery } from "react-responsive";
import { useCategory, useProducts} from "#hooks";
export const Category: React.FC<CategoryProps> = () => {
const foo = useMemo(() => (
// some logic here..
), []);
const { query } = useRouter();
const { category, loading: categoryLoading } = useCategory(query.slug);
const isDesktop = useMediaQuery({ query: "(min-width: 1280px)" });
const handleFoo = useCallback(() => {
// some logic here...
}, []);
const { products, loading: productsLoading } = useProducts(category.id);
useEffect(() => {
// some logic here...
}, []);
return (<h1>Some big template here...</h1>);
}
I'm struggling to find some kind of information about how to place (sort) hooks inside components.
A few questions:
Should third-party hooks go right at the start of component function body, or should be go last?
Should useMemo hooks be above useEffect/useCallback hooks?
Where should I place project custom hooks?
I know that is simple answer to that question is just to be consistent, but I want to know, what react community thinks, how you write your functional components with hooks?
After looking through the React Documentation, I found a couple rules in regards to hooks: https://reactjs.org/docs/hooks-rules.html#:~:text=Instead%2C%20always%20use%20Hooks%20at,multiple%20useState%20and%20useEffect%20calls.
Also this article: https://blog.bitsrc.io/best-practices-with-react-hooks-69d7e4af69a7
The second articles gives a good list of best practices when it comes to React Hooks.
1.) Class based components have a more structured order do to all of the lifecycle methods that you are working with componentDidMount ect.
2.) When it comes to a functional component, then the order/structure really is not enforced. From the article:
It’s recommended to first declare state variables with useState hook, then write the subscriptions with useEffect hook followed by any function relevant to the component’s job.
Then finally, you return the elements to be rendered by the browser...
In other words, what makes sense you as a developer will probably be alright. If this is a project that you are doing with other developers. Developing a coding type standard based on your work might be a good idea.
Let me know if that answers your question :)

Can you use componentDidMount() on a React class that doesn't extend Component?

I've created my React class like such:
const MyMap = () => {
componentDidMount() {
...
}
return {
...
}
}
I realized that componentDidMount() is not being recognized and is not working. Is this because I didn't extend React.Component? Also, is there an alternative I can use for the React class I created?
you could use useEffect hook
useEffect(() => {
// write your logic here
}, []);
as they mention here
The Effect Hook, useEffect, adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes

React Hook "useState" cannot be called inside a callback. Using useMediaQuery responsive JS media query

I'm trying to use responsive javascript media queries using useMediaQuery however I can't get it to work, I get: -
Error message:
"useState" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function
Playground
https://stackblitz.com/edit/react-ts-5vseqr?file=media-query.ts
I think it's erroring on line 4 of media-query.ts
import { useState, useEffect } from 'react'
const useMediaQuery = (query: string) => {
const [match, setMatch] = useState(false)
useEffect(() => {
const updateMatch = () => setMatch(window.matchMedia(query).matches)
updateMatch()
window.matchMedia(query).addEventListener('change', updateMatch)
return () => {
window.matchMedia(query).removeEventListener('change', updateMatch)
}
}, [query])
return match
}
export default useMediaQuery
What you've done here is writing a custom hook(useMediaQuery). You've done that properly so no issues there. Above code snipped is fine.
The problem is in the index.tsx file when you try to use the above custom hook that you've written. As the error suggests your custom hook is called outside the react component there in line 7 of index.tsx.
You have to move the useMediaQuery call inside the App component. Also currently your App component is a class component which you have to convert to a functional component to use hooks inside it.
here's the adjusted code:
https://stackblitz.com/edit/react-ts-m6rwpd?file=index.tsx

Where should I make AJAX and API calls in React.js function components?

I've been learning more about React.js function components and have started transitioning one of my React.js applications to use them instead of the standard react components. In my react components I had been making AJAX/API call(s) in the componentDidMount() function. Since that function doesn't exist in function components I am unsure where to put them.
I couldn't find the answer on the React.js site, the only page I could find on AJAX and APIs shows making those calls with react standard components in the componentDidMount() function.
This is what React hooks gives us - ways to do side effects in functional components:
https://reactjs.org/docs/hooks-effect.html
from the doc page:
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
for example:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
//do an ajax call here
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
You can use react-pure-lifecycle to add lifecycle functions to functional components.
Example:
import React, { Component } from 'react';
import lifecycle from 'react-pure-lifecycle';
const methods = {
componentDidMount(props) {
//ajax call here
}
};
const Channels = props => (
<h1>Hello</h1>
)
export default lifecycle(methods)(Channels);

Categories