TUTORIAL
TUTORIAL
md 2023-12-17
Setup
traditional Vite app
removed boilerplate
provided some assets (css, data)
just so we can focus on important stuff
removed , so it's less logs
Advanced Topics
/tutorial directory
work in the starter folder
complete code in the final folder
in order to work on topic import component from 'starter'
in order to test final import component from 'final'
setup challenges
in the beginning examples with numbers and buttons
Setup Challenge :
the reason for bug - we don't trigger re-render (reference next lecture)
1 / 61
TUTORIAL.md 2023-12-17
useState Basics
useState hook
returns an array with two elements: the current state value, and a function that we can use to update
the state
accepts default value as an argument
state update triggers re-render
2 / 61
TUTORIAL.md 2023-12-17
// setCount('pants');
};
return (
<div>
<h4>You clicked {count} times</h4>
<button className='btn' onClick={handleClick}>
Click me
</button>
</div>
);
};
In a React application, the initial render is the first time that the component tree is rendered to the DOM. It
happens when the application first loads, or when the root component is first rendered. This is also known as
"mounting" the components.
Re-renders, on the other hand, happen when the component's state or props change, and the component
needs to be updated in the DOM to reflect these changes. React uses a virtual DOM to optimize the process
of updating the actual DOM, so that only the necessary changes are made.
There are a few ways that you can trigger a re-render in a React component:
By changing the component's state or props. When the component's state or props change, React will
re-render the component to reflect these changes.
When the parent element re-renders, even if the component's state or props have not changed.
Setup Challenge :
import data
3 / 61
TUTORIAL.md 2023-12-17
return (
<div>
{people.map((person) => {
const { id, name } = person;
return (
<div key={id} className='item'>
<h4>{name}</h4>
</div>
);
})}
</div>
);
};
2. remove items
<h4>{name}</h4>
<button onClick={() => removeItem(id)}>remove</button>
</div>
);
})}
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={() => setPeople([])}
>
clear items
</button>
</div>
);
};
Setup Challenge :
return (
<>
<h3>{name}</h3>
<h3>{age}</h3>
<h4>Enjoys To: {hobby}</h4>
<button className='btn' onClick={displayPerson}>
show john
</button>
</>
);
};
Automatic Batching
In React, "batching" refers to the process of grouping multiple state updates into a single update. This can be
useful in certain cases because it allows React to optimize the rendering of your components by minimizing
the number of DOM updates that it has to perform.
By default, React uses a technique called "auto-batching" to group state updates that occur within the same
event loop into a single update. This means that if you call the state update function multiple times in a short
period of time, React will only perform a single re-render for all of the updates.
React 18 ensures that state updates invoked from any location will be batched by default. This will batch state
updates, including native event handlers, asynchronous operations, timeouts, and intervals.
Switch to Object
6 / 61
TUTORIAL.md 2023-12-17
Setup Challenge :
Keep in mind that the state update function setState does not immediately mutate the state. Instead, it
schedules an update to the state and tells React that it needs to re-render the component. The actual state
update will be performed as part of the next rendering cycle. Be mindful when you need to set state value
based on a different state value.
trivial example
7 / 61
TUTORIAL.md 2023-12-17
If you want to update the state immediately and synchronously, you can pass a function to setState that
receives the previous state as an argument and returns the new state. For example:
setState((prevState) => {
return { ...prevState, value: newValue };
});
This can be useful if you need to update the state based on the previous state, or if you need to update the
state synchronously.
setTimeout Example
Code Example
8 / 61
TUTORIAL.md 2023-12-17
repeat
repeat
repeat ..................................................
useEffect Basics
9 / 61
TUTORIAL.md 2023-12-17
useEffect is a hook in React that allows you to perform side effects in function components.There is no need
for urban dictionary - basically any work outside of the component. Some examples of side effects are:
subscriptions, fetching data, directly updating the DOM, event listeners, timers, etc.
useEffect hook
accepts two arguments (second optional)
first argument - cb function
second argument - dependency array
by default runs on each render (initial and re-render)
cb can't return promise (so can't make it async)
if dependency array empty [] runs only on initial render
sayHello();
// useEffect(() => {
// console.log('hello from useEffect');
// });
useEffect(() => {
console.log('hello from useEffect');
}, []);
return (
<div>
<h1>value : {value}</h1>
<button className='btn' onClick={() => setValue(value + 1)}>
click me
</button>
</div>
);
};
export default UseEffectBasics;
Multiple Effects
10 / 61
TUTORIAL.md 2023-12-17
useEffect(() => {
console.log('hello from first useEffect');
}, [value]);
useEffect(() => {
console.log('hello from second useEffect');
}, [secondValue]);
return (
<div>
<h1>value : {value}</h1>
<button className='btn' onClick={() => setValue(value + 1)}>
value
</button>
<h1>second value : {secondValue}</h1>
<button className='btn' onClick={() => setSecondValue(secondValue + 1)}>
second value
</button>
</div>
);
};
export default MultipleEffects;
Fetch Data
Setup Challenge :
useEffect(() => {
// you can also setup function outside
const fetchData = async () => {
try {
const response = await fetch(url);
const users = await response.json();
setUsers(users);
} catch (error) {
console.log(error);
}
};
fetchData();
}, []);
return (
<section>
<h3>github users</h3>
<ul className='users'>
{users.map((user) => {
const { id, login, avatar_url, html_url } = user;
return (
<li key={id}>
<img src={avatar_url} alt={login} />
<div>
<h5>{login}</h5>
<a href={html_url}>profile</a>
</div>
</li>
);
})}
</ul>
</section>
);
};
export default FetchData;
Cleanup Function
Setup Challenge :
inside second component create useEffect and run it only on initial render
Vanilla JS
13 / 61
TUTORIAL.md 2023-12-17
useEffect(() => {
// console.log('hmm, this is interesting');
const someFunc = () => {
// some logic here
};
window.addEventListener('scroll', someFunc);
return () => window.removeEventListener('scroll', someFunc);
}, []);
fetching data replaced by libraries - react query, rtk query, swr or next.js
function Example() {
const { data, error, isLoading } = useHook('url', fetcher);
14 / 61
TUTORIAL.md 2023-12-17
Vanilla JS
useEffect(() => {
setTimeout(() => {
// done fetching data
setIsLoading(false);
}, 3000);
}, []);
Setup Challenge :
useEffect(() => {
const fetchUser = async () => {
try {
const resp = await fetch(url);
const user = await resp.json();
console.log(user);
} catch (error) {
// fetch only cares about network errors
// will work with axios
console.log(error);
}
};
fetchUser();
}, []);
Data Fetching :
16 / 61
TUTORIAL.md 2023-12-17
useEffect(() => {
const fetchUser = async () => {
try {
const resp = await fetch(url);
const user = await resp.json();
// console.log(user);
setUser(user);
} catch (error) {
setIsError(true);
console.log(error);
}
// hide loading
setIsLoading(false);
};
fetchUser();
}, []);
// order matters
// don't place user JSX before loading or error
if (isLoading) {
return <h2>Loading...</h2>;
}
if (isError) {
return <h2>There was an error...</h2>;
}
return (
<div>
<img
style={{ width: '150px', borderRadius: '25px' }}
src={user.avatar_url}
alt={user.name}
/>
<h2>{user.name}</h2>
<h4>works at {user.company}</h4>
<p>{user.bio}</p>
</div>
);
};
export default MultipleReturnsFetchData;
17 / 61
TUTORIAL.md 2023-12-17
Unlike for example Axios, by default, the fetch() API does not consider HTTP status codes in the 4xx or 5xx
range to be errors. Instead, it considers these status codes to be indicative of a successful request,
try {
const resp = await fetch(url);
// console.log(resp);
if (!resp.ok) {
setIsError(true);
setIsLoading(false);
return;
}
Challenge :
return (
<div>
<img
style={{ width: '100px', borderRadius: '25px' }}
src={avatar_url}
alt={name}
/>
<h2>{name}</h2>
<h4>works at {company}</h4>
<p>{bio}</p>
18 / 61
TUTORIAL.md 2023-12-17
</div>
);
before returns
after returns
return (
<div>
<img
style={{ width: '100px', borderRadius: '25px' }}
src={avatar_url}
alt={name}
/>
<h2>{name}</h2>
<h4>works at {company}</h4>
<p>{bio}</p>
</div>
);
Vanilla JS
const someObject = {
name: 'jo koy',
};
// this is cool
someObject.name; // returns 'jo koy'
someObject.propertyThatDoesNotExist; // returns undefined
// this is ok
const randomList = [];
19 / 61
TUTORIAL.md 2023-12-17
useEffect(() => {
fetchData();
}, []);
if (condition) {
return <h2>Hello There</h2>;
}
// this will also fail
useEffect(() => {
console.log('hello there');
}, []);
return <h2>example</h2>;
};
Vanilla JS
In JavaScript, a value is considered "truthy" if it is evaluated to true when used in a boolean context. A value is
considered "falsy" if it is evaluated to false when used in a boolean context.
false 0 (zero) "" (empty string) null undefined NaN (Not a Number) All other values, including objects and
arrays, are considered truthy.
For example:
const x = 'Hello';
const y = '';
const z = 0;
if (x) {
console.log('x is truthy');
}
if (y) {
console.log('y is truthy');
} else {
console.log('y is falsy');
}
if (z) {
console.log('z is truthy');
} else {
console.log('z is falsy');
}
// Output:
// "x is truthy"
// "y is falsy"
// "z is falsy"
In this example, the variable x is a non-empty string, which is considered truthy, so the first if statement is
executed. The variable y is an empty string, which is considered falsy, so the else block of the second if
statement is executed. The variable z is the number 0, which is considered falsy, so the else block of the third
if statement is executed.
Vanilla JS
In JavaScript, short-circuit evaluation is a technique that allows you to use logical operators (such as && and
||) to perform conditional evaluations in a concise way.
The && operator (logical AND) returns the first operand if it is "falsy", or the second operand if the first
operand is "truthy".
21 / 61
TUTORIAL.md 2023-12-17
For example:
const x = 0;
const y = 1;
The || operator (logical OR) returns the first operand if it is "truthy", or the second operand if the first operand
is "falsy".
For example:
const x = 0;
const y = 1;
Short-circuit evaluation can be useful in cases where you want to perform a certain action only if a certain
condition is met, or you want to return a default value if a certain condition is not met.
For example:
function displayName(name) {
return name || 'Anonymous';
}
In this example, the displayName() function returns the name property of the user object if it exists, or
"Anonymous" if the name property is not present. This is done using the || operator and short-circuit
evaluation.
Setup Challenge :
22 / 61
TUTORIAL.md 2023-12-17
Vanilla JS (Optional) The ! operator is a logical operator in JavaScript that negates a boolean value. It is
equivalent to the not operator in other programming languages.
For example:
23 / 61
TUTORIAL.md 2023-12-17
You can use the ! operator to test if a value is not truthy or falsy:
let val = 0;
if (!val) {
console.log('val is falsy');
}
You can also use the ! operator to convert a value to a boolean and negate it:
val = '';
bool = !val; // bool is now true
24 / 61
TUTORIAL.md 2023-12-17
</div>
) : (
<div>
<h2>please login</h2>
</div>
)}
</div>
);
};
Ternary Operator
Vanilla JS
In JavaScript, the ternary operator is a way to concisely express a simple conditional statement. It is often
called the "conditional operator" or the "ternary conditional operator".
If condition is truthy, the operator will return expression1. If condition is falsy, it will return expression2.
Jobster Example
Jobster
Toggle Challenge
25 / 61
TUTORIAL.md 2023-12-17
Initial Setup
return (
<div>
<button className='btn' onClick={toggleAlert}>
toggle alert
</button>
{showAlert && <Alert />}
</div>
);
};
Improvements
User Challenge
return (
<div>
{user ? (
<div>
<h4>hello there, {user.name}</h4>
<button className='btn' onClick={logout}>
logout
</button>
</div>
) : (
<div>
<h4>Please Login</h4>
<button className='btn' onClick={login}>
login
</button>
</div>
)}
</div>
);
};
/tutorial/04-project-structure/starter
/components/componentName.jsx /screens/componentName.jsx
27 / 61
TUTORIAL.md 2023-12-17
import in App.jsx
/tutorial/04-project-structure/starter
create index.jsx
in App.jsx
/tutorial/04-project-structure/starter
Leverage Javascript
/tutorial/05-leverage-javascript/starter
Setup Challenge
List.jsx
Person.jsx
// const img =
// (images && images[0] && images[0].small && images[0].small.url) || avatar;
// Combining with the nullish coalescing operator ??
// const img = images?.[0]?.small?.url ?? avatar;
// ?? vs || - please utilize the search engine
return (
<div>
<img src={img} alt={name} style={{ width: '50px' }} />
<h4>{name} </h4>
<p>Nickname : {nickName}</p>
</div>
);
}
In JavaScript, when defining a function, you can specify default values for its parameters. This means that if a
caller of the function does not provide a value for a particular parameter, the default value will be used
instead. Default parameters are defined by assigning a value to the parameter in the function definition.
For example, consider the following function, which takes two parameters, x and y, and returns their sum:
function add(x, y) {
return x + y;
}
If we call this function with only one argument, it will return NaN because y is undefined.
30 / 61
TUTORIAL.md 2023-12-17
function add(x = 0, y = 0) {
return x + y;
}
Now, if we call add(3), the function will return 3, because the default value of 0 is used for the y parameter.
n JavaScript, the optional chaining operator (?.) is a new feature that allows you to access properties of an
object without worrying about whether the object or the property is null or undefined. It's a shorthand for a
common pattern of checking for null or undefined before accessing an object's property.
For example, consider the following code, which accesses the firstName property of an object:
If the name property is null or undefined, this code will throw an error. To prevent this, we can use the
optional chaining operator:
console.log(person?.name?.first);
Now, if the person.name is null or undefined, this code will simply return undefined instead of throwing an
error. This make the code more robust and readable.
31 / 61
TUTORIAL.md 2023-12-17
Email
</label>
<input type='email' className='form-input' id='email' />
</div>
<button type='submit' className='btn btn-block'>
submit
</button>
</form>
);
};
export default ControlledInputs;
/>
</div>
<div className='form-row'>
<label htmlFor='email' className='form-label'>
Email
</label>
<input
type='email'
className='form-input'
id='email'
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<button type='submit' className='btn btn-block'>
submit
</button>
</form>
);
};
export default ControlledInputs;
User Challenge
when user submits the form add new person to the list
Extra Challenge
// do something
console.log(name);
// if no value, do nothing
if (!name) return;
// if value, setup new user and add to current users
const fakeId = Date.now();
console.log(fakeId);
// const newUser = { id: fakeId, name: name };
const newUser = { id: fakeId, name };
const updatedUsers = [...users, newUser];
setUsers(updatedUsers);
// set back to empty
setName('');
};
{users.map((user) => {
return (
<div key={user.id}>
<h4>{user.name}</h4>
<button onClick={() => removeUser(user.id)} className='btn'>
remove
</button>
</div>
);
})}
</div>
34 / 61
TUTORIAL.md 2023-12-17
);
};
export default UserChallenge;
Multiple Inputs
35 / 61
TUTORIAL.md 2023-12-17
Email
</label>
<input
type='email'
className='form-input'
id='email'
name='email'
value={user.email}
onChange={handleChange}
/>
</div>
{/* password */}
<div className='form-row'>
<label htmlFor='password' className='form-label'>
Password
</label>
<input
type='password'
className='form-input'
id='password'
name='password'
value={user.password}
onChange={handleChange}
/>
</div>
Other Inputs
FormData API
The FormData interface provides a way to construct a set of key/value pairs representing form fields and their
values, which can be sent using the fetch() or XMLHttpRequest.send() method. It uses the same format a form
would use if the encoding type were set to "multipart/form-data".
38 / 61
TUTORIAL.md 2023-12-17
/>
</div>
e.currentTarget
In React, e.currentTarget returns the DOM element that triggered the event.
The Object.fromEntries() static method transforms a list of key-value pairs into an object.
console.log(obj);
// Expected output: Object { foo: "bar", baz: 42 }
reset()
The reset() method is a built-in method in HTML that can be used to reset all form controls to their initial
values. When this method is called on a form element, it will clear any user-entered data and reset the values
of all form elements to their default values.
useRef
console.log(refContainer);
// {current:null}
// set value ourselves or DOM node
useEffect(() => {
// console.log(refContainer.current);
refContainer.current.focus();
});
useEffect(() => {
if (!isMounted.current) {
isMounted.current = true;
return;
}
console.log('re-render');
}, [value]);
return (
<div>
<form className='form' onSubmit={handleSubmit}>
<div className='form-row'>
<label htmlFor='name' className='form-label'>
Name
</label>
<input
type='text'
id='name'
ref={refContainer}
className='form-input'
/>
</div>
<button type='submit' className='btn btn-block'>
submit
</button>
</form>
<h1>value : {value}</h1>
<button onClick={() => setValue(value + 1)} className='btn'>
increase
</button>
</div>
);
};
40 / 61
TUTORIAL.md 2023-12-17
Custom Hooks
useToggle.js
Challenge
useFetchPerson.js
useEffect(() => {
const fetchUser = async () => {
try {
41 / 61
TUTORIAL.md 2023-12-17
Generic Fetch
useFetch.js
useEffect(() => {
// change name
const fetchData = async () => {
try {
const resp = await fetch(url);
if (!resp.ok) {
setIsError(true);
setIsLoading(false);
return;
}
// change to response
const response = await resp.json();
setData(response);
} catch (error) {
42 / 61
TUTORIAL.md 2023-12-17
setIsError(true);
// console.log(error);
}
// hide loading
setIsLoading(false);
};
// invoke fetch data
fetchData();
}, []);
Context API
Challenge
Navbar.jsx
in Navbar.jsx setup
extra challenge
please login
Navbar.jsx
43 / 61
TUTORIAL.md 2023-12-17
NavLinks.jsx
UserContainer.jsx
44 / 61
TUTORIAL.md 2023-12-17
</button>
</>
) : (
<p>Please Login</p>
)}
</div>
);
};
export default UserContainer;
useReducer
Challenge
45 / 61
TUTORIAL.md 2023-12-17
// JSX
{
people.length < 1 ? (
<button className='btn' style={{ marginTop: '2rem' }} onClick={resetList}>
reset
</button>
) : (
<button className='btn' style={{ marginTop: '2rem' }} onClick={clearList}>
clear
</button>
);
}
Remove useState
// default/initial state
const defaultState = {
people: data,
};
// reducer function
// whatever state is returned from the function is the new state
// dispatch({type:'SOME_ACTION'}) an action
// handle it in reducer, return new state
return (
<div>
{/* switch to state */}
{state.people.map((person) => {
const { id, name } = person;
47 / 61
TUTORIAL.md 2023-12-17
return (
<div key={id} className='item'>
<h4>{name}</h4>
<button onClick={() => removeItem(id)}>remove</button>
</div>
);
})}
{/* switch to state */}
{state.people.length < 1 ? (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={resetList}
>
reset
</button>
) : (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={clearList}
>
clear
</button>
)}
</div>
);
};
First Dispatch
const defaultState = {
people: data,
isLoading: false,
};
48 / 61
TUTORIAL.md 2023-12-17
49 / 61
TUTORIAL.md 2023-12-17
const defaultState = {
people: data,
};
{state.people.length < 1 ? (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={resetList}
>
reset
</button>
) : (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={clearList}
50 / 61
TUTORIAL.md 2023-12-17
>
clear
</button>
)}
</div>
);
};
const defaultState = {
people: data,
};
return (
<div>
{/* switch to state */}
51 / 61
TUTORIAL.md 2023-12-17
{state.people.map((person) => {
const { id, name } = person;
return (
<div key={id} className='item'>
<h4>{name}</h4>
<button onClick={() => removeItem(id)}>remove</button>
</div>
);
})}
{/* switch to state */}
{state.people.length < 1 ? (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={resetList}
>
reset
</button>
) : (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={clearList}
>
clear
</button>
)}
</div>
);
};
const defaultState = {
people: data,
};
52 / 61
TUTORIAL.md 2023-12-17
console.log(action);
if (action.type === CLEAR_LIST) {
return { ...state, people: [] };
}
if (action.type === RESET_LIST) {
return { ...state, people: data };
}
if (action.type === REMOVE_ITEM) {
let newPeople = state.people.filter(
(person) => person.id !== action.payload.id
);
return state;
};
return (
<div>
{/* switch to state */}
{state.people.map((person) => {
const { id, name } = person;
return (
<div key={id} className='item'>
<h4>{name}</h4>
<button onClick={() => removeItem(id)}>remove</button>
</div>
);
})}
{/* switch to state */}
{state.people.length < 1 ? (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={resetList}
>
reset
</button>
53 / 61
TUTORIAL.md 2023-12-17
) : (
<button
className='btn'
style={{ marginTop: '2rem' }}
onClick={clearList}
>
clear
</button>
)}
</div>
);
};
Import / Export
copy/paste reducer
import actions
import data
export/import reducer
Performance
When the component's state or props change, React will re-render the component to reflect these
changes.
When the parent element re-renders, even if the component's state or props have not changed.
lower state
54 / 61
TUTORIAL.md 2023-12-17
<button
className='btn'
onClick={() => setCount(count + 1)}
style={{ marginBottom: '1rem' }}
>
count {count}
</button>
);
};
export default Counter;
</form>
);
};
export default Form;
React.memo()
React.memo is a higher-order component (HOC) in React that allows you to memoize a component. This
means that if the input props to the component have not changed, the memoized component will return the
same result from the previous render, instead of re-rendering. This can help improve performance by avoiding
unnecessary render cycles.
The React.memo function takes a functional component as its argument and returns a new component that
has the same behavior, but with the added optimization of checking if the props have changed. If the props
have not changed, the memoized component will return the cached result from the previous render.
Function "Gotcha"
UseCallback
The useCallback hook is a hook in React that allows you to memoize a function. It takes two arguments: the
first is the function you want to memoize, and the second is an array of dependencies. The hook will return a
memoized version of the function that only changes if one of the values in the dependency array changes.
56 / 61
TUTORIAL.md 2023-12-17
By memoizing the function, you can avoid unnecessary re-renders and improve the performance of your React
application. The function will only be re-created if one of its dependencies changes, otherwise the same
instance of the function will be returned. This can be useful in situations where you have an expensive
function that you only want to recompute when its dependencies change.
function MyComponent() {
const [data, setData] = useState([]);
const handleClick = useCallback(() => {
console.log(data);
}, [data]);
return (
<div>
<button onClick={handleClick}>Click me</button>
</div>
);
}
In this example, the handleClick function is memoized using useCallback and the data prop is passed as a
dependency. This means that the handleClick function will only be re-created if the data prop changes.
useEffect(() => {
fetchData();
}, [fetchData]);
57 / 61
TUTORIAL.md 2023-12-17
useMemo
The useMemo hook is a hook in React that allows you to memoize a value. It takes two arguments: the first is
a function that returns the value you want to memoize, and the second is an array of dependencies. The hook
will return the memoized value that will only change if one of the values in the dependency array changes.
By memoizing a value, you can avoid unnecessary calculations and improve the performance of your React
application. The value will only be recalculated if one of its dependencies changes, otherwise the same
instance of the value will be returned. This can be useful in situations where you have an expensive calculation
that you only want to recompute when its dependencies change.
return (
<div>
{processedData.map((item) => (
<div key={item}>{item}</div>
))}
</div>
);
}
In this example, the processedData value is memoized using useMemo and the data prop is passed as a
dependency. This means that the processedData value will only be recalculated if the data prop changes.
58 / 61
TUTORIAL.md 2023-12-17
useTransition
JS Nuggets - Array.from
useTransition is a React Hook that lets you update the state without blocking the UI.
startTransition(() => {
const newItems = Array.from({ length: 5000 }, (_, index) => {
return (
<div key={index}>
<img src='/vite.svg' alt='' />
</div>
);
});
setItems(newItems);
});
};
return (
<section>
<form className='form'>
<input
type='text'
className='form-input'
value={text}
onChange={handleChange}
/>
</form>
<h4>Items Below</h4>
{isPending ? (
'Loading...'
) : (
<div
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
marginTop: '2rem',
}}
59 / 61
TUTORIAL.md 2023-12-17
>
{items}
</div>
)}
</section>
);
};
export default LatestReact;
Suspense API
The Suspense API is a feature in React that allows you to manage the loading state of your components. It
provides a way to "suspend" rendering of a component until some data has been fetched, and display a
fallback UI in the meantime. This makes it easier to handle asynchronous data loading and provide a smooth
user experience in your React application.
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<DataComponent />
</Suspense>
);
}
startTransition(() => {
const newItems = Array.from({ length: 5000 }, (_, index) => {
return (
<div key={index}>
<img src='/vite.svg' alt='' />
</div>
);
});
60 / 61
TUTORIAL.md 2023-12-17
setItems(newItems);
});
};
return (
<section>
<form className='form'>
<input
type='text'
className='form-input'
value={text}
onChange={handleChange}
/>
</form>
<h4>Items Below</h4>
{isPending ? (
'Loading...'
) : (
<div
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
marginTop: '2rem',
}}
>
{items}
</div>
)}
<button onClick={() => setShow(!show)} className='btn'>
toggle
</button>
{show && (
<Suspense fallback={<h4>Loading...</h4>}>
<SlowComponent />
</Suspense>
)}
</section>
);
};
export default LatestReact;
return (
<Suspense fallback={<h4>Loading...</h4>}>
{/* rest of the logic */}
<section>{show && <SlowComponent />}</section>
</Suspense>
);
61 / 61