replacing componentDidMount with useEffect - reactjs

I was going through React Hooks docs and it mentioned
If you’re familiar with React class lifecycle methods, you can think
of useEffect Hook as componentDidMount, componentDidUpdate, and
componentWillUnmount combined.
Suppose I have a class component right now where in componentDidMount I am doing something like this
componentDidMount() {
MapboxGL.setTelemetryEnabled(false);
}
As far as I can recall, Component did mount is only called once in lifecycle?
If I were to use react hooks then it would be something like this
useEffect(() => {
MapboxGL.setTelemetryEnabled(false);
});
This would call my function everytime state changes in react functional hooks component? Wouldn't it be redundant to call MapboxGL.setTelemetryEnabled(false); to call this everytime? when you only want to do it once component have mounted?
React docs have showed how useEffect can replace multiple lifecycle methods but I am still unable to comprehend how react hooks can replace componentDidMount?
Also, Just a side note question, Can you make a full fledge app using hooks (something like foursquare or instagram?)

You need to add a dependency array for it to know when to recall this hook. An empty dep array will only call it once aka "on mount". And if you don't provide a dep array then it will just be called on every re-render.
useEffect(() => {
MapboxGL.setTelemetryEnabled(false);
}, []);

You can create a flag and if the flag is false/true then only perform that action. something as simple as this
useEffect(() => {
if (something) {
MapboxGL.setTelemetryEnabled(false);
setSomething(false)
}
});
or if you only need hook once, you can do what Matt have suggested
useEffect(() => {
MapboxGL.setTelemetryEnabled(false);
}, []);

Related

Trigger some API once react state empty

I want to trigger An API to do some actions when the value in the react state be empty, Is there a way in react state hook to achieve that?
If you are using a functional component you can use the "useEffect" hook with a proper dependency.
Class base components you might choose (if I understand your situation properly) something like the "componentWillUnmount()" method.
You could have a useEffect hook with the state as a dependency, in-which you can check if the state is empty and act accordingly.
Example:
const [state, setState] = useState([]);
useEffect(() => {
if (state.length !== 0) {
return;
}
// Can make your API call here (preferably call a function that does it)
// and then set the state.
setState(...);
}, [state]);
useEffect is a hook that accepts a callback as the first argument, and a dependency array as the second.
The callback will execute upon re-render whenever any of the dependencies in the array change.
Note: this is relevant only for functional components, for class-based component we have the componentDidUpdate lifecycle hook.

Using redux data in the useEffect hooks

I am now trying to call an API using data from the redux store.
Let say I got 2 API calls, Api A and Api B Inside the parent component I already called the API A and save the data inside the redux already.
Now I am in another component. I need to call Api B. But API B has a params, which I will get from API A. So Inside the Second component, I am using useEffect hook to call the data.
To get the params from the redux, I am using useSelector Hook.
Inside the second component, UseEffect Hook is something like this:
useEffect(() => {
let splitText = cartList?.OrderDTO?.DeliveryCountry;
let deliveryAddressId = splitText?.split(',');
if (cartList.OrderDTO?.DeliveryCountry !== '') {
dispatch(getShippingMethodById(token.access_token, deliveryAddressId));
} else {
dispatch(
getShippingMethodById(
token.access_token,
cartList.OrderDTO?.CustomerAddressId,
),
}
}, []);
So in the useEffect hook, I got the deliveryAddressId from redux. To draw in data from the redux into component, I am using useSelector hook
let cartList = useSelector((state) => state.productReducer.cartList);
The problem is that I always get undefined for cartlist when ever I tried to access it inside the useEffect hook
So the dispatch called are always getting undefined. So What can I do to make this hooks works?
You should add cartList to your dependency array, so the useEffect hook watches for updates to that piece of state. As it is written now, the useEffect only runs on the first render, where cartList is probably undefined.
React - useEffect Docs
useEffect(() => {
let splitText = cartList?.OrderDTO?.DeliveryCountry;
let deliveryAddressId = splitText?.split(',');
if (cartList.OrderDTO?.DeliveryCountry !== '') {
dispatch(getShippingMethodById(token.access_token, deliveryAddressId));
} else {
dispatch(
getShippingMethodById(
token.access_token,
cartList.OrderDTO?.CustomerAddressId,
),
}
}, [cartList]); // Add 'cartList' to your dependency array here
Solution is that you add cartList inside the dependency array.
useEffect(() => {
// All your logic inside
}, [cartList]);
I don't have info about the complete parent-child component structure, but from what I understood with the error I can explain the issue.
You are using [], for useEffect dependency, which means the callback inside useEffect will be triggered only once when the component mounts.
It is possible that when your component mounted, the API call in the parent was not complete, and you have still have undefined in store for cartList.
To check this hypothesis you can add console.log in API response and
inside the useEffect.
What else you can do?
You can not render the child component until you have data from the API call.
Why adding cartList in the dependency array fixed the issue?
By dependency array inside useEffect, your useEffect call back will be
called whenever the values in the dependency array change + on the
mount.
So, at the time of mount of the child component, useEffect's callback will trigger (cartList as undefined), then when the API call is successful and after that data is pushed in state, your child component will rerender and will retrigger the callback inside useEffect with the actual(which you got from API and pushed in store) cartList data.

Does ComponentDidMount not work with react hooks?

I have been trying to use componentDidMount on a project but it only appears to work when the file uses classes.
With hooks you can use useEffect to get same result.
This one would work like componentDidMount
useEffect(() = > {
}, [])
If you put a callback in empty array then it would work when you use that callback
According to the React docs:
You can’t use Hooks inside a class component, but you can definitely
mix classes and function components with Hooks in a single tree.
Instead of componentDidMount you can use useEffect instead, with an empty array as its dependency which will serve the same purpose of running code when the component mounts:
useEffect(() = > {
// ... code
}, [])
The above answer:
With hooks you can use useEffect to get same result.
This one would work like componentDidMount
useEffect(() = > {
}, [])
is right except:
If you put a callback in empty array then it would work when you use that callback
that empty array is where you would list dependencies that upon change would re-run the function. The empty array turns it into run only once.

react.js hook (too many re-renders)

I'm new to react.js hook. Not sure about why the following code doesn't work.
import React,{useEffect,useState} from "react"
function App() {
const [fruit,setFruit] = useState("orange");
setFruit("apple")
return (
<div>
<h1>{fruit}</h1>
</div>
);
}
export default App;
The error says that
Too many re-renders. React limits the number of renders to prevent an infinite loop.
You're setting the state inside the functional component body (The setFruit("apple") line) which will cause the component to re-render and when this happens all the component body will rerun again which will cause another set state call and so on which ultimately causes an infinite loop.
If you want to set the state when the component is mounting, You can use the useEffect hook to achieve that like so:
useEffect(() => {
setFruit("apple")
}, []);
Read more about the hook here.
you need to use useEffect
useEffect(() => {
setFruit("apple")
}, [])
The actual pattren of react is that when you set a state it cause rerender that means component re run again and recompile every line of code if it found a set state fucntion again it rerender and that's what happening in youe code. To prevent this you can use useEffect hook which accepts a callback function and a dependency array
For Example
useEffect(() => {}, []);
The code in every useEffect will run with first time component mount and if you want to run the code again you need to pass dependency in 2nd argument of useEffect which decide that if the dependency change it's value the code in useEffect will run again.
In your case you can set state like this
useEffect(() => {
setFruit("apple")
}, []);

How can I ensure that a line of code is executed only once using React hooks in a functional component?

I want a line of code in a react component to be executed only when the component is mounted, and not when it re-renders. In a stateful component, I would do this in componentDidMount/componentWillMount method.
How can I do this using hooks?
I believe you are looking for reacts useEffect hook. It is the hook replacement for componentDidMount, componentDidUpdate, and componentWillUnmount. You can use it like this:
useEffect(() => {
console.log("only executed once")
}, [])
Note the empty array as second argument, which defines the dependencies for this effect. In this case you want to have no dependency, so that the effect wont be executed again.
There is a good article on how to replace the previous lifecycle functions with hooks available here.
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {}, [])
React Docs. Hooks-Using the Effect Hook. - > https://reactjs.org/docs/hooks-effect.html

Resources