Node Js
$npm install -g n
$sudo n [version.number]
Vite
$cd project-folder
$npm create vite@latest .
$npm install
$npm run dev
ReactJs
$npx create-react-app my-app
Eslint plugin react hook
$npm install eslint-plugin-react-hooks --save-dev
https://reactjs.org/docs/hooks-rules.html
- Do not modify the state directly or Manualy
const [count,setCount] = useState(0)
//count = 90 Do not update state manually
useEffect(()=>{
//count = 40 Do not do this! //Do not update manually
setCount(90) //use the setCount //Do this
},[]) //Empty array dependencies to prevent continued update of useEffect if component change
//Run only at the start of component
useEffect(()=>{
},[count]) //useEffect update if "count" variable change //Infinite loop
useEffect(()=>{
}) //Continue update everytime changes detected //Infinite loop
- Call Hook always on the top level of component/component function
useState('Mary') // 1. Read the name state variable (argument is ignored)
// useEffect(persistForm) // π΄ This Hook was skipped!
useState('Poppins') // π΄ 2 (but was 3). Fail to read the surname state variable
useEffect(updateTitle) // π΄ 3 (but was 4). Fail to replace the effect
- Put condition inside hook
useEffect(function persistForm() {
// π We're not breaking the first rule anymore
if (name !== '') {
localStorage.setItem('formData', name);
}
});
- Do not use useEffect() for fetching Data
Race condition // π΄
No instant back button // π΄
No initial HTML content // π΄
// Best to use
useQuery() // π
userSWR() // π
use() // π
or Any framework // π
- fetch()
const App = () => {
const [user, setUser] = setState('')
useEffect(()=>{
const controller = new AbortController();
const signal = controller.signal;
fetch(`https://jsonplaceholder.typecode.com/users/${id}`, { signal })
.then((res)=>res.json())
.then((data)=>{
setUser(data);
});
//CleanUp function
return()=>{
controller.abort();
console.log('cancelled');
}
},[id]);
return(
<div>
<p>{user.username}</p>
<p>{user.email}</p>
</div>
)
}
export default App
- Axios()
const App = () => {
const [user, setUser] = setState('')
useEffect(()=>{
const cancelToken = axios.CancelToken.source()
axios.get(`https://jsonplaceholder.typecode.com/users/${id}`, { cancelToken:cancelToken.token })
.then((res)=>{
setUser(res.data);
}).catch(err=>{
if(axios.isCancel(err)){
console.log('cancelled');
}
});
//CleanUp function
return()=>{
cancelToken.cancel();
console.log('cancelled');
}
},[id]);
return(
<div>
<p>{user.username}</p>
<p>{user.email}</p>
</div>
)
}
export default App
- Interval
const App = () => {
const [number, setNumber] = useState(0)
useEffect(()=>{
console.log('useEffect run')
const interval = setInterval(()=>{
setNumber((prev)=>prev + 1)
});
//CleanUp function
return()=>{
clearInterval(interval);
}
},[1000])
return(
<div><p>{number}</p></div>
)
}
export default App
memoizing value, to compute the value when necessary only
const [a, setA] = useState(0);
const [b, setB] = useState(0);
const sum = useMemo(()=> {
console.log('Computing...')
return a + b;
},[a, b]);
return (
<>
<p>{ sum }</p>
<button onClick={()=> setA(a + 1) }>Increment A</button>
<button onClick={()=> setA(b + 1) }>Increment B</button>
</>
)
memoizing the function, when passing function as prop so its reference remain the same
function ChildComponent({ onClick }){
return(
<>
<button onClick={ onClick }>ClickMe</button>
</>
)
}
const [count, setCount] = useState(0);
const incrementCount = useCallback(()=> {
setCount(prevCount => prevCount + 1);
},[setCount]);
return (
<>
<p>{ count }</p>
<button onClick={ setCount }>Increment</button>
<ChildComponent onClick={ incrementCount } />
</>
)