React - prevent calling useEffect for the first mount [duplicate] - reactjs

This question already has answers here:
Make React useEffect hook not run on initial render
(16 answers)
Closed 9 months ago.
I want to prevent calling my useEffect on the first mount.
how can I do this?
I want the best practice.
I don't want to use if condition
import { useState, useEffect } from "react";
const Counter = () => {
const [count, setCount] = useState(5);
useEffect(() => {
console.log(count);
}, [count]);
return (
<div>
<h1> Counter </h1>
<div> {count} </div>
<button onClick={() => setCount(count + 1)}> click to increase </button>
</div>
);
};
export default Counter;

I found it.
It should be handled by useLayoutEffect and useRef
import { useState, useEffect, useLayoutEffect, useRef } from "react";
const Counter = () => {
const [count, setCount] = useState(5);
const firstUpdate = useRef(true);
useLayoutEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
console.log(count);
});
return (
<div>
<h1> Counter </h1>
<div> {count} </div>
<button onClick={() => setCount(count + 1)}> click to increase </button>
</div>
);
};
export default Counter;

Related

React Component not updating text when I change it

When I click the increment button I expect the value displayed to go up but it stays the same
`
import * as React from 'react';
const MyComponent = () => {
var count = 0;
return (
<div>
<h1>Hello World</h1>
<button onClick={() => count++}>{count}</button>
</div>
);
};
`
You're not going to force a re render so your updated variable won't show.
import React, {useState} from 'react';
const MyComponent = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>Hello World</h1>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
);
};
In React you have to use state for rendering or updating.
This is example of increasing and decreasing counter with useState hook.
import React, { useState } from 'react';
export function App(props) {
const [count, setCount] = useState(0);
const handleIncrease = () => {
setCount(count + 1);
};
const handleDecrease = () => {
setCount(count === 0 ? 0 : count - 1);
};
return (
<div className='App'>
<div>
<h1>Hello World</h1>
<button onClick={handleIncrease}>Increase</button>
<button onClick={handleDecrease}>Decrease</button>
<h3>Count is: {count}</h3>
</div>
</div>
);
}
You need to use useState hook so the component knows when to rerender and display new data.
I also recommend using useCallback hook to create memoized functions so you prevent unnecessary rerenders of your component (I know in this example it's an overkill but it's still good to know that).
You shouldn't, if possible, return arrow functions on your handlers like onClick - this will also cause the your component to not create new instances of your functions on each render, hence better performance (again not really relevant in this super simple case but a good thing to know nevertheless).
Here are some docs that you can read, these are a really good place to get started with React.
Here's also the code:
const MyComponent = () => {
const [count, setCount] = useState(0);
const handleCountIncrease = useCallback(() => {
setCount((c) => c + 1);
}, [setCount]);
return (
<div>
<h1>Hello World</h1>
<button onClick={handleCountIncrease}>{count}</button>
</div>
)
}
I see here you are using Functional component, so have you tried using React hooks? useState() for example:
import * as React from 'react';
const MyComponent = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>Hello World</h1>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div> ); };
Try this maybe?

what is the design flaw causing the infinite loop in this component?

I've created a basic React component as a sandbox. I added a doSomething() function to the component which simply displays an alert on useEffect(). However, the alert is getting called in an infinite loop. So obviously, there's something wrong with the design. Any idea what the design issue is with this component which is causing the infinite loop? What steps would you recommend to redesign this component in order to fix that issue?
import {Repository} from '../data/Repository';
import { useEffect , useState} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { decrement, increment } from '../features/counter/counterSlice';
import { setIsValid } from '../features/userManagement/userManagementSlice';
export const UserManagement = () => {
const [userTestData, setUserTestData] = useState([]);
const [userCount, setUserCount] = useState(0);
const count = useSelector((state) => state.counter.value)
const isValid2 = useSelector((state) => state.userManagement.isValid2)
const dispatch = useDispatch()
const doSomething = () => {
alert('about to do something');
}
useEffect(() => {
doSomething();
setUserTestData(Repository.getUserTestData());
})
useEffect(() => {
setUserCount(userTestData.length);
}, [userTestData])
//debugger;
return(
<>
<div>
{
userTestData.map((x) => {
return <div key={x.Id}>{x.FirstName}</div>
})
}
</div>
<div>there are {userCount} users</div>
<div>
{/* PARENT INPUT VALIDATION */}
<div style={{height:100}}>
<button onClick={() => dispatch(setIsValid())}>
TOGGLE VALIDATION
</button>
{isValid2 ? 'true' : 'false'}
</div>
{/* COUNTER */}
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
</>
)
}
The issue here.
useEffect(() => {
doSomething();
setUserTestData(Repository.getUserTestData());
})
You didn't add array of dependences to useEffect, so it's callback will be excuted on each render of the component, and as you set a State by setUserTestData, so the component will still re-render in infinite loop.
To fix.
useEffect(() => {
doSomething();
setUserTestData(Repository.getUserTestData());
}, [])

simultaneous updates of React in React

Is it possible to update one state in React and in the same render, can we use the updated value to update another state?
import "./styles.css";
import {useState} from 'react';
export default function App() {
const [num, setNum] = useState(0)
const [txt, setTxt] = useState(0)
handleClick= () =>{
setNum(num+1)
setTxt(num+1)
}
return (
<div className="App">
<input type="submit" value="button" onClick={handleClick} />
<h1>{num}</h1>
<h1>{txt}</h1>
</div>
);
}
In the above example, both num and txt are initially set to 0.
Clicking the button for the first time would increase both num and txt to 1 and it would update both to 2 when clicked again and so on.
Is there way to get the num updated to 1 as soon as setNum(num+1) is called, so that it can update it from 0 to 1 and so while calling setTxt(num+1), it can update it directly to 2?
Yes, you can do that using the useEffect hook with the num as a dependency.
Here's a CodeSandbox:
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [num, setNum] = useState(0);
const [txt, setTxt] = useState(0);
const handleClick = () => {
setNum(num + 1);
};
useEffect(() => {
if (num > 0) {
setTxt(num + 1);
}
}, [num]);
return (
<div className="App">
<input type="submit" value="button" onClick={handleClick} />
<h1>{num}</h1>
<h1>{txt}</h1>
</div>
);
}
If the actual state is just a number and not something complex like an array/object then you can simply do this:
const handleClick = () => {
setNum(num + 1);
setTxt(num + 2);
};

want to know why componentWillUnmount execute when a component update

App.js
import React from "react";
import CounterOne from "./CounterOne";
function App() {
const [display, setDisplay] = React.useState(true);
return (
<>
{display && <CounterOne />}
<button
onClick={() => {
setDisplay(!display);
}}
>
display
</button>
</>
);
}
export default App;
CounterOne.js
import React, { useState } from "react";
function CounterOne() {
const [count, setCount] = useState(0);
React.useEffect(() => {
console.log("component did update");
return () => {
console.log("component will unmount");
};
}, [count]);
return (
<div>
<p>Count is {count}</p>
<button
onClick={() => {
setCount(0);
}}
>
reset
</button>
<button
onClick={() => {
setCount(count + 5);
}}
>
Add 5
</button>
<button
onClick={() => {
setCount(count - 1);
}}
>
Sub 1
</button>
</div>
);
}
export default CounterOne;
When i hit the Add 5 or sub 1 button, the component re-render then in browser console it prints
component will unmount
component did update
i am confuse why will unmount part execute when the update of state taking place
Because when you change a state in a component, React will re-render the whole component. So the old component will be unmounted first, triggering the return callback in useEffect. When a new component is mounted, the logic inside useEffect will be triggered again, hence you see the "component did update" after the "component will unmount" message. More on useEffect here What is the expected return of `useEffect` used for?.

useState counter flickers after clicking the button

export const App2 =()=>{
const [counter,setCounter]=useState(0)
setTimeout(()=>setCounter(counter+1),1000)
return(
<div> {counter}
<button onClick={()=>{setCounter(counter+1)}}> Plus</button>
</div>
)
}
I recorded a video and uploaded it to youtube. I have no idea why this instability happens and switching tabs made it normal again. Anyone to enlighten? I just made a slight modification to this code
setTimeout causes an effect, so we should put it inside a useEffect() hook. Also, since setCounter depends on the previous counter state, we can pass an updater function to setCounter which receives the previous state value.
import React, { useCallback, useEffect } from "react";
export const App2 = () => {
const [counter, setCounter] = useState(0);
const increment = useCallback(() => {
setCounter((counter) => counter + 1);
}, []);
useEffect(() => {
const id = setTimeout(increment, 1000);
return () => clearTimeout(id);
}, [increment]);
return (
<div>
{" "}
{counter}
<button onClick={increment}> Plus</button>
</div>
);
};

Resources