Skip to content
English
On this page

React

Conditional Rendering

Inline If with && Operator

ts
return (
	<div>
	{ listProducts.length > 0 &&
		<ul>{listProducts}</ul>
	}
	{ listProducts.length == 0 &&
		<ul>No Products to display</ul>
	}
	</div>
);

Inline If-Else with Conditional Operator

ts
return (
<div>
	{listProducts.length > 0 ? (
		<ul>{listProducts}</ul>
	) : (
		<ul>No Products to display</ul>
	)}
</div>
);

Using the State Hook

ts
import { useState } from 'react'

const Counter = () => {
	const [counter, setCounter] = useState<number>(0)
}

As you can see, we are declaring the counter state with the setCounter setter and we are specifying that we will only accept numbers, and finally, we set the initial value with zero. In order to test our state, we need to create a method that will be triggered by the onClick event:

ts
const Counter = () => {
	const [counter, setCounter] = useState<number>(0)
	const handleCounter = (operation) => {
	if (operation === 'add') {
		return setCounter(counter + 1)
	}
		return setCounter(counter - 1)
	}	
}
ts
return (
<p>
	Counter: {counter} <br />
	<button onClick={() => handleCounter('add')}>+ Add</button>
	<button onClick={() => handleCounter('subtract')}>- Subtract</button>
</p>
)

Rules of Hooks

Rule 1: Only call Hooks at the top level

"Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That's what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls."

Rule 2: Only call Hooks from React Functions

"Don't call Hooks from regular JavaScript functions. Instead, you can:

  • Call Hooks from React function components.
  • Call Hooks from custom Hooks (we'll learn about them on the next page). By following this rule, you ensure that all stateful logic in a component is clearly visible from its source code."

useMemo

useCallback

js
import React, {useState, useCallback} from 'react';

// Define an arrayValue prop
const UseCallbackComponent = ({arrayValue}) => {

  // Memoize callback with useCallback
  // Ensure the reference is always the same as long as the function doesn't change
  // So children components do not re-render due to a redundant variable reference change
  // Since functions are pass by reference
  const createArray = useCallback(() => {
    return [ arrayValue, arrayValue + 1, arrayValue + 2 ];
  }, [ arrayValue ]);
  
  // Let's pass createArray to a fictional subcomponent
  // By using useCallback in this case, we can avoid the reference of createArray
  // to change during every render, and save subsequent renders in subcomponents
  return <>
      <PrintArray arrayFunction={createArray} />
    </>;
  
  // useCallback is similar to useMemo but for functions/callbacks instead of variable values
};
ts
const handleDelete = useCallback((taskId: number) => {
    const newTodoList = todoList.filter((todo: Todo) => todo.id !== taskId)
    setTodoList(newTodoList)
  }, [todoList])

useEffect

ts
const printTodoList = () => {
	console.log('Changing todoList')
}

useEffect(() => {
	printTodoList()
}, [todoList])
ts
import { useState, useEffect } from 'react'
import Geolocation from './Geolocation'

const GeolocationContainer = () => {
  const [latitude, setLatitude] = useState<number | null>(null)
  const [longitude, setLongitude] = useState<number | null>(null)

  const handleSuccess = ({ coords: { latitude, longitude } }: { coords: { latitude: number; longitude: number }}) => { 
    setLatitude(latitude) 
    setLongitude(longitude)
  }

  useEffect(() => { 
    if (navigator.geolocation) { 
      navigator.geolocation.getCurrentPosition(handleSuccess)
    } 
  }, [])


  return ( 
    <Geolocation latitude={latitude} longitude={longitude} /> 
  )
}

export default GeolocationContainer

useReducer

ts
type Note = {
	id: number
	note: string
}
type Action = {
	type: string
	payload?: any
}
type ActionTypes = {
	ADD: 'ADD'
	UPDATE: 'UPDATE'
	DELETE: 'DELETE'
}
const actionType: ActionTypes = {
	ADD: 'ADD',
	DELETE: 'DELETE',
	UPDATE: 'UPDATE'
}

const initialNotes: Note[] = [
	{
		id: 1,
		note: 'Note 1'
	},
	{
		id: 2,
		note: 'Note 2'
	}
]
ts
const reducer = (state: Note[], action: Action) => {
	switch (action.type) {
		case actionType.ADD:
			return [...state, action.payload]
		case actionType.DELETE:
			return state.filter(note => note.id !== action.payload)
		case actionType.UPDATE:
			const updatedNote = action.payload
			return state.map((n: Note) => n.id === updatedNote.id ?	updatedNote : n)
		default:
			return state
	}
}
ts
const Notes = () => {
	const [notes, dispatch] = useReducer(reducer, initialNotes)
	const [note, setNote] = useState('')
	...
}
ts
const handleSubmit = (e: ChangeEvent<HTMLInputElement>) => {
	e.preventDefault()
	const newNote = {
		id: Date.now(),
		note
	}
	dispatch({ type: actionType.ADD, payload: newNote })
}

Higher-Order Functions (HOFs)

FunctionAsChild

ts
const FunctionAsChild = ({ children }) => children()

<FunctionAsChild>
	{() => <div>Hello, World!</div>}
</FunctionAsChild>