You may not need an effect - React (2023)

Effects are an emergency exit from the React paradigm. They allow you to "exit" React and sync your components with some external system like a widget, network, or non-React DOM browser. If there is no external system involved (for example, if you want to update the state of a component when some props or state change), you don't need an effect. Removing unnecessary effects will make your code easier to follow, faster to execute, and less prone to errors.

you'll learn

  • Why and how to remove unnecessary effects from your components
  • How to cache expensive calculations without effects
  • How to reset and adjust the state of components without effects
  • How to share logic between event handlers
  • What logic should be moved to the event handlers
  • How to notify core components about changes

How to remove unnecessary effects

There are two common cases where you don't need effects:

  • You don't need effects to transform the data for rendering.For example, suppose you want to filter a list before displaying it. You might be tempted to write an effect that updates a state variable when the list changes. However, this is inefficient. When you update the state, React first calls your component's functions to calculate what should be on the screen. So React will"commit"these changes to the DOM, refreshing the screen. Then React will run your effects. if your effectalsoimmediately update the status, this restarts the whole process from scratch! To avoid unnecessary render passes, transform all data at the top level of your components. This code will automatically run whenever your accessories or status change.
  • You don't need Effects to handle user events.For example, suppose you want to send a/api/buyPOST request and display a notification when the user purchases a product. In the Buy button click event handler, you know exactly what happened. When an effect runs, you don't knowThatthe user did (for example, which button was clicked). This is why you will normally handle user events in the corresponding event handlers.

Youdoneeds effects forsynchronizewith external systems. For example, you can write an effect that keeps a jQuery widget in sync with the React state. You can also get data with Effects: for example, you can synchronize search results with the current search query. Remember that the modernPhotosprovide built-in data retrieval mechanisms that are more efficient than writing Effects directly into your components.

To help you get the right intuition, let's look at some common concrete examples!

Update status based on accessories or status

Suppose you have a component with two state variables:First namemilast name. Do you want to calculate afull namethem concatenating them. Also, would you likefull nameto update every timeFirst nameolast namechange. Your first instinct might be to add afull namestate variable and update it in an Effect:

function Mould() {

constant [First name, setName]=useState('taylor');

constant [last name, establecerApellido]=useState('Fast');

// 🔴 Avoid: redundant state and unnecessary effect

constant [full name, setFullName]=useState('');

use effect(() => {

setFullName(First name+''+last name);

}, [First name, last name]);

// ...

}

This is more complicated than it needs to be. It's also inefficient: it performs a full render pass with a stale value tofull name, then immediately re-renders with the updated value. Remove the state variable and the effect:

function Mould() {

constant [First name, setName]=useState('taylor');

constant [last name, establecerApellido]=useState('Fast');

// ✅ Good: calculated during rendering

constant full name=First name+''+last name;

// ...

}

When something can be computed from existing props or states,do not put in stateInstead, calculate it during rendering.This makes your code faster (avoids additional "cascading" updates), simpler (eliminates some of the code), and less error prone (avoids errors caused by different state variables not being in sync with each other). . If this approach sounds new to you,thinking about reactexplains what should go into the state.

Expensive calculation caching

This component calculatesvisibleTodotaking theallreceives by props and filtering them according to thefilterMedium. You might be tempted to store the result in the state and update it from an Effect:

function Chores({ all, filter }) {

constant [novoTodo, defineNovoTodo]=useState('');

// 🔴 Avoid: redundant state and unnecessary effect

constant [visibleTodo, setVisibleTodos]=useState([]);

use effect(() => {

setVisibleTodos(getFilteredTodos(all, filter));

}, [all, filter]);

// ...

}

As in the previous example, this is unnecessary and inefficient. First, remove the state and the effect:

function Chores({ all, filter }) {

constant [novoTodo, defineNovoTodo]=useState('');

// ✅ This is fine if getFilteredTodos() is not slow.

constant visibleTodo=getFilteredTodos(all, filter);

// ...

}

Usually this code is good! But maybegetFilteredTodos()is it slow or do you have too manyall. In that case, you don't want to recalculategetFilteredTodos()if some unrelated state variable likenovoTodochange.

You can cache (or"to memorize") an expensive calculation that involves you in ause noteHook:

matter { use note, useState } of 'react';

function Chores({ all, filter }) {

constant [novoTodo, defineNovoTodo]=useState('');

constant visibleTodo=use note(() => {

// ✅ Don't run again unless everything is changed or the filter is changed

return getFilteredTodos(all, filter);

}, [all, filter]);

// ...

}

Or, written in a single line:

matter { use note, useState } of 'react';

function Chores({ all, filter }) {

constant [novoTodo, defineNovoTodo]=useState('');

// ✅ Don't re-execute getFilteredAll() unless all or filter changes

constant visibleTodo=use note(() => getFilteredTodos(all, filter), [all, filter]);

// ...

}

This tells React that you don't want the inner function to be executed again unless youallofilterchange.React will remember the return value ofgetFilteredTodos()during initial rendering. During the next few renders, it will check ifallofilterThey are different. If they are the same as last time,use notewill return the last stored result. But if they are different, React will call the inner function again (and store its result).

The role involveduse noteruns during rendering, so this only works forpure calculations.

dive deep

How to know if a calculation is expensive?

In general, unless you're creating or iterating thousands of objects, it's probably not expensive. If you want more confidence, you can add a console log to measure the time spent on a code snippet:

console.tempo('filter array');

constant visibleTodo=getFilteredTodos(all, filter);

console.horaFim('filter array');

Perform the interaction you are measuring (for example, writing a post). You will see records likefilters array: 0.15mson your console. If the total time recorded is a significant amount (say,1 msor more), it might make sense to memorize this calculation. As an experiment, you can group the calculation intouse noteTo check if the total time recorded has decreased for that interaction or not:

console.tempo('filter array');

constant visibleTodo=use note(() => {

return getFilteredTodos(all, filter); // Ignored if everything and the filter were not changed

}, [all, filter]);

console.horaFim('filter array');

use notewill not do thefirstrender faster. It just helps you skip unnecessary work on updates.

Keep in mind that your machine is probably faster than your users, so it's a good idea to test performance with artificial slowdown. For example, Chrome offers acpu throttlingoption for that.

Also note that measuring development performance will not provide the most accurate results. (for example whenstrict modeis on, you'll see each component rendered twice instead of once.) To get the most accurate times, build your app for production and test it on a device like your users.

Reset all state when a support changes

To beProfile pagecomponent gets aUser IDMedium. The page contains a comment entry and uses acommentstate variable to hold its value. One day, you notice a problem: when browsing from one profile to another, thecommentthe state is not reset. As a result, it's easy to accidentally post a comment on the wrong user's profile. To fix the problem, you want to clear thecommentstate variable wheneverUser IDchanges:

export standard function Profile page({ User ID }) {

constant [comment, setComment]=useState('');

// 🔴 Avoid: reset state on prop change in an effect

use effect(() => {

setComment('');

}, [User ID]);

// ...

}

This is inefficient becauseProfile pageand its children will first render with the stale value and then render again. It's also complicated because you have to do it inallcomponent having some state insideProfile page. For example, if the comment's UI is nested, you'll also want to clear the nested comment's state.

Instead, you can tell React that each user's profile is conceptually onedifferentprofile, giving it an explicit key. Split your component in two and pass onekeyouter to inner component attribute:

export standard function Profile page({ User ID }) {

return (

<Profile

User ID={User ID}

key={User ID}

/>

);

}

function Profile({ User ID }) {

// ✅ This and any other state below will be reset on key change automatically

constant [comment, setComment]=useState('');

// ...

}

(Video) Goodbye, useEffect - David Khourshid

Normally, React preserves state when the same component is rendered in the same location.pasoUser IDlike onekeyfor himProfilecomponent, you are asking React to handle twoProfilecomponents with differentUser IDas two different components that should not share any state.Each time the key (which you set inUser ID) changes, React will recreate the DOM andreset statedoProfilecomponent and all its children. Now himcommentThe field will be automatically cleared when browsing between profiles.

Note that in this example, only the outer partProfile pagethe component is exported and is visible to other files in the project. component representationProfile pageyou don't need to pass the key: they passUser IDas regular support. The factProfile pagepasses like akeyinsideProfilecomponent is an implementation detail.

Set some status when an accessory changes

Sometimes you may want to reset or modify some state on a media change, but not all of it.

To beListcomponent receives a list ofElementsas a support and holds the selected item on theselectionVariable state. Do you want to reset theselectionfornullevery time heElementsprop takes a different array:

function List({ Elements }) {

constant [esReversa, establecerIsReverse]=useState(FALSE);

constant [selection, setSelection]=useState(null);

// 🔴 Avoid: set state on prop change in an effect

use effect(() => {

setSelection(null);

}, [Elements]);

// ...

}

This is also not ideal. every time heElementschange theListand its child components will be rendered with a deprecated patternselectionvalue first. React will then update the DOM and launch Effects. Finally, thesetSelection(null)call will cause the file to be re-renderedListand its child components, starting this whole process over again.

Start by removing the effect. Instead, set the state directly during rendering:

function List({ Elements }) {

constant [esReversa, establecerIsReverse]=useState(FALSE);

constant [selection, setSelection]=useState(null);

// Better: adjust state during rendering

constant [previous elements, setPrevItems]=useState(Elements);

con (Elements!==previous elements) {

setPrevItems(Elements);

setSelection(null);

}

// ...

}

Storing information from previous rendershow this can be hard to understand, but it's better than updating the same state in an effect. In the above example,setSelectionis called directly during a render. React will re-render theList immediatelyafter dating areturnstatement. React did not render theListchildren or updated the DOM yet, so this allows theListchildren jump making obsoleteselectionvalor.

When you update a component during rendering, React discards the returned JSX and tries to re-render immediately. To avoid very slow cascading retries, React only allows you to update thesamecomponent state during a render. If you update the state of another component during a render, you'll see an error. A condition likeitems !== previous itemsit is necessary to avoid loops. You can modify the state this way, but any other side effects (such as changing the DOM or setting timeouts) must remain in the event handlers or Effects tokeep the components pure.

While this pattern is more efficient than an effect, most components don't need it either.No matter how you do it, prop-based tuning state or other state makes your data flow more difficult to understand and debug. Always make sure you canreset all status with one keyocalculate everything while you renderinstead of. For example, instead of storing (and resetting) thearticle, you can store the selectedID make element:

function List({ Elements }) {

constant [esReversa, establecerIsReverse]=useState(FALSE);

constant [selected id, setSelectedId]=useState(null);

// ✅ Improved: Calculate everything while rendering

constant selection=Elements.meet(article => article.I was going===selected id)??null;

// ...

}

Now there is no need to "adjust" the state. If the item with the selected ID is in the list, it will remain selected. But theselectioncalculated during rendering will benullbecause no matching element was found. This behavior is different but possibly better because most changes toElementskeep selection.

Share logic between event handlers

Let's say you have a product page with two buttons (Buy and Checkout) that allow you to purchase that product. You want to display a notification every time the user places the product in the cart. Vocationshow notification()in both button click handlers it looks repetitive, so you might be tempted to put that logic into an effect:

function product page({ products, add to cart }) {

// 🔴 Avoid: event-specific logic inside an effect

use effect(() => {

con (products.isInCart) {

show notification(`Added ${products.name} to shopping cart!`);

}

}, [products]);

function driveBuyClick() {

add to cart(products);

}

function handleCheckoutClick() {

add to cart(products);

navigate to('/To check');

}

// ...

}

This effect is unnecessary. It is also likely to cause errors. For example, suppose your application "remembers" the shopping cart between page reloads. If you add a product to the cart once and refresh the page, the notification will appear again. It will continue to appear every time you refresh the page for that product. This is becauseproduct.isincartit will beTRUEon page load, then the above effect will callshow notification().

When you're not sure if some code should be in an effect or an event handler, ask yourselfbecausethis code needs to run. Use effects only for the code that needs to be executedbecausethe component was displayed to the user.In this example, the notification should appear because the userpressed the button, not because the page was displayed! Remove the effect and put the shared logic in a function called from both event handlers:

function product page({ products, add to cart }) {

// ✅ Good: Event-specific logic called event handlers

function buy product() {

add to cart(products);

show notification(`Added ${products.name} to shopping cart!`);

}

function driveBuyClick() {

buy product();

}

function handleCheckoutClick() {

buy product();

navigate to('/To check');

}

// ...

}

This removes the unnecessary effect and fixes the bug.

Sending a POST request

To beMouldThe component sends two types of POST requests. Sends an analytic event when mounted. When you complete the form and click the Submit button, you will send a POST request to the/api/registerfinal point:

function Mould() {

constant [First name, setName]=useState('');

constant [last name, establecerApellido]=useState('');

// ✅ Good: This logic should execute because the component was displayed

use effect(() => {

post('/analysis/event', { name of the event: 'visit_form' });

}, []);

// 🔴 Avoid: event-specific logic inside an effect

constant [jsonToSend, establecerJsonParaEnviar]=useState(null);

use effect(() => {

con (jsonToSend!==null) {

post('/api/register', jsonToSend);

}

}, [jsonToSend]);

function manipulateSend(mi) {

mi.prevenirPredeterminado();

establecerJsonParaEnviar({ First name, last name });

(Video) React 18 Tutorial - You Might Not Need an Effect

}

// ...

}

Let's apply the same criteria as in the previous example.

The analytical POST request should remain in a single effect. This occurs because thereasonsending the analytic event is that the form has been displayed. (Would fire twice in development, butsee herefor how to deal with it).

However the/api/registerThe POST request is not caused by the form beingunfolded. You only want to send the request at a specific time: when the user presses the button. this should just happenin this specific interaction. Remove the second effect and move this POST request to the event handler:

function Mould() {

constant [First name, setName]=useState('');

constant [last name, establecerApellido]=useState('');

// ✅ Good: This logic is executed because the component was displayed

use effect(() => {

post('/analysis/event', { name of the event: 'visit_form' });

}, []);

function manipulateSend(mi) {

mi.prevenirPredeterminado();

// ✅ Good: the event-specific logic is in the event handler

post('/api/register', { First name, last name });

}

// ...

}

When you choose whether you want to put some logic in an event handler or an effect, the main question you need to answer iswhat kind of logicIt's from the user's perspective. If this logic is caused by a specific interaction, keep it in the event handler. If it is caused by the userseerthe component on the canvas, keep it in the Effect.

calculation strings

Sometimes you may be tempted to chain effects that adjust one part of the state based on another state:

function Game() {

constant [card, setCard]=useState(null);

constant [GoldCardCount, definirGoldCardCount]=useState(0);

constant [redondo, setRound]=useState(1);

constant [esGameOver, setIsGameOver]=useState(FALSE);

// 🔴 Avoid: Chains of effects that adjust state only to activate each other

use effect(() => {

con (card!==null&&card.oro) {

definirGoldCardCount(C => C+1);

}

}, [card]);

use effect(() => {

con (GoldCardCount>3) {

setRound(r => r+1)

definirGoldCardCount(0);

}

}, [GoldCardCount]);

use effect(() => {

con (redondo>5) {

setIsGameOver(TRUE);

}

}, [redondo]);

use effect(() => {

alert('Good game!');

}, [esGameOver]);

function handlePlaceCard(NextCard) {

con (esGameOver) {

to throw Error('The game is over.');

} other {

setCard(NextCard);

}

}

// ...

There are two problems with this code.

One problem is that it's very inefficient: the component (and its children) have to re-render between eachdefinecall jail In the example above, in the worst case (setCard→ render →definirGoldCardCount→ render →setRound→ render →setIsGameOver→ render) there are three unnecessary representations of the tree below.

Even if it wasn't slow, as your code evolves you will encounter cases where the "string" you wrote doesn't conform to the new requirements. Imagine you're adding a way to scroll through the game's play history. You would do this by updating each state variable to a value from the past. However, setting thecardstate to a value from the past would trigger the effect chain again and change the data it is displaying. This code is usually rigid and brittle.

In that case, it's better to compute what it can during rendering and wrap the state in the event handler:

function Game() {

constant [card, setCard]=useState(null);

constant [GoldCardCount, definirGoldCardCount]=useState(0);

constant [redondo, setRound]=useState(1);

// ✅ Calculate what you can during rendering

constant esGameOver=redondo>5;

function handlePlaceCard(NextCard) {

con (esGameOver) {

to throw Error('The game is over.');

}

// ✅ Calculate all the next state in the event handler

setCard(NextCard);

con (NextCard.oro) {

con (GoldCardCount<=3) {

definirGoldCardCount(GoldCardCount+1);

} other {

definirGoldCardCount(0);

setRound(redondo+1);

con (redondo===5) {

alert('Good game!');

}

}

}

}

// ...

This is much more efficient. Also, if you implement a way to view game history, you can now set each state variable to a move from the past without triggering the effect chain that adjusts all other values. If you need to reuse logic across multiple event handlers, you canextract a functionand call it from these controllers.

Remember that within event handlers,The state behaves like a snapshot.For example, even after turning onsetRound(round + 1), oredondoThe variable will reflect the value at the time the user clicked the button. If you need to use the following value for calculations, set it manually inconst nextRound = ronda + 1.

In some cases, youcan notcalculate the next state directly in the event handler. For example, imagine a form with multiple dropdowns where the options for the next dropdown depend on the selected value of the previous dropdown. So an effects chain is appropriate because you are synchronizing with the network.

initializing the application

Some of the logic should only be executed once when the app is loaded.

You might be tempted to put it in an effect on the top level component:

function Application() {

// 🔴 Avoid: Logic effects that only need to be executed once

use effect(() => {

loadDataFromLocalStorage();

check authentication token();

}, []);

// ...

}

However, you will soon discover thatruns twice in development.This can cause problems, for example it could invalidate the auth token because the function is not designed to be called twice. In general, its components must be resistant to reassembly. This includes your top levelApplicationcomponent.

While it may never be practically reassembled in production, following the same constraints across all components makes the code easier to move and reuse. Whether to execute any logiconce per app loadinstead ofonce per component assembly, add a top-level variable to keep track of whether it has already been executed:

leave fezInit=FALSE;

function Application() {

use effect(() => {

con (!fezInit) {

fezInit=TRUE;

// ✅ Runs only once per application load

loadDataFromLocalStorage();

check authentication token();

}

(Video) You should Avoid these React useEffect Mistakes

}, []);

// ...

}

You can also run it during module initialization and before application rendering:

con (kind of ventana!=='Undefined') { // Check if we are running in the browser.

// ✅ Runs only once per application load

check authentication token();

loadDataFromLocalStorage();

}

function Application() {

// ...

}

The code at the top level runs once when your component is imported, even if it's not rendered. To avoid slowdowns or unexpected behavior when importing arbitrary components, do not abuse this pattern. Keep your application-wide initialization logic in the root component modules, such asApplication.jsor at the entry point of your application.

Notify parent components about state changes

Let's say you're writing alevercomponent with an interioris connectedstate that can be bothTRUEoFALSE. There are a few different ways to change it (by clicking or dragging). You want to notify the parent component whenever theleverinternal state changes, so it exposes aInsteadevent and call it from an Effect:

function lever({ Instead }) {

constant [is connected, setIsOn]=useState(FALSE);

// 🔴 Avoid: onChange handler runs too late

use effect(() => {

Instead(is connected);

}, [is connected, Instead])

function manipularClick() {

setIsOn(!is connected);

}

function handleDragEnd(mi) {

con (is closer to the right edge(mi)) {

setIsOn(TRUE);

} other {

setIsOn(FALSE);

}

}

// ...

}

As before, this is not ideal. EITHERleverit first refreshes its state and React refreshes the screen. React then runs Effect, which callsInsteadFunction passed from a parent component. Now the parent component will update its own state, starting another render pass. It would be better to do everything in one pass.

Delete the effect and update the state instead.bothcomponents within the same event handler:

function lever({ Instead }) {

constant [is connected, setIsOn]=useState(FALSE);

function refresh toggle(nextIsOn) {

// ✅ Good: Performs all updates during the event that triggered them

setIsOn(nextIsOn);

Instead(nextIsOn);

}

function manipularClick() {

refresh toggle(!is connected);

}

function handleDragEnd(mi) {

con (is closer to the right edge(mi)) {

refresh toggle(TRUE);

} other {

refresh toggle(FALSE);

}

}

// ...

}

With this approach, bothleverThe component and its parent component update their state during the event. Reactbatch updatesof different components together, so there will only be one render pass.

You can also remove the status entirely and instead receiveis connectedfrom the parent component:

// ✅ Also nice: the component is fully controlled by its parent

function lever({ is connected, Instead }) {

function manipularClick() {

Instead(!is connected);

}

function handleDragEnd(mi) {

con (is closer to the right edge(mi)) {

Instead(TRUE);

} other {

Instead(FALSE);

}

}

// ...

}

"Raising the State"allows the parent component to fully control thelevertoggle the parent's own state. This means that the main component will have to contain more logic, but there will be less overall state to worry about. Anytime you're trying to keep two different state variables in sync, try increasing the state.

pass data to parent

To beNiñoThe component gets some data and passes it to thePaicomponent in an effect:

function Pai() {

constant [data, set data]=useState(null);

// ...

return <Niño in get={set data} />;

}

function Niño({ in get }) {

constant data=you are in SomeAPI();

// 🔴 Avoid: Passing data to the parent in an Effect

use effect(() => {

con (data) {

in get(data);

}

}, [in get, data]);

// ...

}

In React, data flows from parent components to their children. When you see something wrong on the screen, you can trace where the information came from by moving up the component chain until you find which component has gone through the wrong bracket or is in the wrong state. When child components update the state of their parent components in Effects, the data flow becomes very difficult to trace. Since both the child and the parent need the same data, let the parent component get that data andto transmitinstead, to the child:

function Pai() {

constant data=you are in SomeAPI();

// ...

// ✅ Good: Pass data to child

return <Niño data={data} />;

}

function Niño({ data }) {

// ...

}

This is simpler and keeps the data flow predictable: data flows from parent to child.

Subscribe to an external store

Sometimes your components may need to sign some data outside of the React state. This data could come from a third-party library or from a built-in browser API. Since this data can change without React's knowledge, you must manually subscribe your components. This is usually done with an effect, for example:

function useOnlineStatus() {

// Not ideal: manual storage signature in an effect

(Video) All useEffect Mistakes Every Junior React Developer Makes

constant [is online, setIsOnline]=useState(TRUE);

use effect(() => {

function update status() {

setIsOnline(browser.online);

}

update status();

ventana.aggregateEventListener('online', update status);

ventana.aggregateEventListener('off', update status);

return () => {

ventana.removeEventListener('online', update status);

ventana.removeEventListener('off', update status);

};

}, []);

return is online;

}

function chat indicator() {

constant is online=useOnlineStatus();

// ...

}

Here, the component subscribes to an external data store (in this case, the browsernavegador.onLineAPI). Since this API does not exist on the server (so it cannot be used for the initial HTML), the state is initially set toTRUE. Every time the value of this data store changes in the browser, the component updates its state.

While it's common to use Effects for this, React has a Hook created specifically for subscribing to preferred external storage. Remove the Effect and replace it with a call tousarSyncExternalStore:

function sign up(call back) {

ventana.aggregateEventListener('online', call back);

ventana.aggregateEventListener('off', call back);

return () => {

ventana.removeEventListener('online', call back);

ventana.removeEventListener('off', call back);

};

}

function useOnlineStatus() {

// ✅ Good: Subscribe to an external store with built-in Hook

return usarSyncExternalStore(

sign up, // React won't resubscribe while passing the same function

() => browser.online, // How to get the customer's value

() => TRUE // How to get the value from the server

);

}

function chat indicator() {

constant is online=useOnlineStatus();

// ...

}

This approach is less error prone than manually synchronizing mutable data to react state with an effect. Typically, you'll write a custom hook likeuseOnlineStatus()above so you don't have to repeat this code in individual components.Learn more about signing up for external React component stores.

get information

Many applications use effects to start getting data. It's quite common to write a fetch effect like this:

function Search results({ consultation }) {

constant [results, define results]=useState([]);

constant [page, definePage]=useState(1);

use effect(() => {

// 🔴 Avoid: Search without cleanup logic

search results(consultation, page).so(json => {

define results(json);

});

}, [consultation, page]);

function handleNextPageClick() {

definePage(page+1);

}

// ...

}

YouNoyou need to move that search to an event handler.

This may seem like a contradiction to previous examples where you had to put logic in event handlers! However, he considers that it is notthe typing eventthis is the main reason to search. Search entries are typically pre-populated from the URL, and the user can navigate back and forth without touching the entry.

It does not matter wherepagemiconsultationcomes from. While this component is visible, you want to keepresults syncedwith network data for the currentpagemiconsultation. That is why it is an Effect.

However, the above code has a bug. Imagine that you are typing"Hola"fast. Soconsultationwill change from"h", for"he","Hola","hell", mi"Hola". This will start separate searches, but there is no guarantee in what order the responses will arrive. For example, him"hell"the answer may comeaftero"Hola"answer. since you are going to callsetResults()Lastly, it will display the wrong search results. Is called"race condition": Two different requests "ran" against each other and arrived in a different order than expected.

To fix the race condition you needadd a cleanup functionto ignore outdated answers:

function Search results({ consultation }) {

constant [results, define results]=useState([]);

constant [page, definePage]=useState(1);

use effect(() => {

leave ignore=FALSE;

search results(consultation, page).so(json => {

con (!ignore) {

define results(json);

}

});

return () => {

ignore=TRUE;

};

}, [consultation, page]);

function handleNextPageClick() {

definePage(page+1);

}

// ...

}

This ensures that when your effect gets data, all but the last requested response will be ignored.

Dealing with race conditions is not the only difficulty in implementing data collection. You might also want to think about response caching (so the user can click back and see the previous screen instantly), getting data from the server (so the initial server-rendered HTML contains the content fetched instead of a spinner), and how to avoid network cascades (so that a child can fetch data without waiting for all the parents).

These issues apply to any UI library, not just React. Solving them is not trivial, which is why modernPhotosprovide built-in data retrieval mechanisms more efficient than data retrieval in Effects.

If you don't use a framework (and don't want to create your own), but want to make fetching Effects data more ergonomic, consider extracting your fetching logic into a custom hook like this example:

function Search results({ consultation }) {

constant [page, definePage]=useState(1);

constant parameters=nuevo URLSearchParams({ consultation, page });

constant results=use data(`/api/search?${parameters}`);

function handleNextPageClick() {

definePage(page+1);

}

// ...

}

function use data(URL) {

constant [data, set data]=useState(null);

use effect(() => {

leave ignore=FALSE;

look for(URL)

.so(answer => answer.json())

.so(json => {

con (!ignore) {

set data(json);

}

});

return () => {

ignore=TRUE;

};

}, [URL]);

return data;

}

You'll probably also want to add some logic to handle errors and track if the content is loading. You can create a hook like this yourself or use one of the many solutions already available in the React ecosystem.While this in itself isn't as efficient as using a framework's built-in fetching mechanism, moving the fetching logic into a custom Hook will make it easier to adopt an efficient fetching strategy later on.

(Video) Why I Don’t Use useEffect In My React Components

In general, whenever you need to write Effects, keep an eye out for when you can extract functionality into a custom Hook with a more declarative and specific API likeuse dataabove. the less rawuse effectcalls you have in your components, the easier it will be to maintain your application.

Recapitulate

  • If you can compute something during rendering, you don't need an effect.
  • To cache expensive computations, adduse noteinstead ofuse effect.
  • To reset the state of an entire component tree, pass akeyFor that.
  • To reset a particular status bit in response to a media change, set it during rendering.
  • Code executed because a component wasunfoldedit should be in Effects, the rest should be in Events.
  • If you need to update the state of multiple components, it's best to do it during a single event.
  • Whenever you're trying to synchronize state variables across different components, consider augmenting the state.
  • You can get data with Effects, but you must implement cleanup to avoid race conditions.

FAQs

What can I use instead of useEffect? ›

One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref ) and you want to make sure it's up-to-date before any other code runs. For example: const ref = React.

What is a React effect? ›

❮ Previous Next ❯ The useEffect Hook allows you to perform side effects in your components. Some examples of side effects are: fetching data, directly updating the DOM, and timers. useEffect accepts two arguments.

Should we use useEffect? ›

If we perform a side effect directly in our component body, it gets in the way of our React component's rendering. Side effects should be separated from the rendering process. If we need to perform a side effect, it should strictly be done after our component renders. This is what useEffect gives us.

What is the second argument of useEffect? ›

useEffect takes two arguments. The first argument passed to useEffect is a function called effect and the second argument (optional) is an array of dependencies. Below is an example. import { useEffect } from "react"; import { render } from "react-dom"; const App = (props) => { useEffect(() => { console.

What is useEffect for dummies? ›

useEffect(callback, dependencies) is the hook that manages the side-effects in functional components. callback argument is a function where to put the side-effect logic. dependencies is a list of dependencies of your side-effect: being props or state values.

Is too many useEffect bad? ›

`useEffect` hook is the worst of all (since it can and is used for just about anything). It is usually used to modify DOM, modify state, call callbacks and so on. If there are several of these hooks with a few dependencies each handling the logic, it's impossible to decipher what's actually happening.

Videos

1. The Power of Not Reacting | Stop Overreacting | How to Control Your Emotions
(Dr. Levry)
2. The Power Of Not Reacting | Respond vs. React With A Narcissist
(Common Ego)
3. Why I avoid useEffect For API Calls and use React Query instead
(CoderOne)
4. Do not use useEffect FOR THIS || React.js Upcoming hook 🔥
(Thapa Technical)
5. UseEffect called twice in React 18 - How to fix it?
(Olli)
6. Top 6 React Hook Mistakes Beginners Make
(Web Dev Simplified)
Top Articles
Latest Posts
Article information

Author: Fr. Dewey Fisher

Last Updated: 06/06/2023

Views: 6328

Rating: 4.1 / 5 (62 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Fr. Dewey Fisher

Birthday: 1993-03-26

Address: 917 Hyun Views, Rogahnmouth, KY 91013-8827

Phone: +5938540192553

Job: Administration Developer

Hobby: Embroidery, Horseback riding, Juggling, Urban exploration, Skiing, Cycling, Handball

Introduction: My name is Fr. Dewey Fisher, I am a powerful, open, faithful, combative, spotless, faithful, fair person who loves writing and wants to share my knowledge and understanding with you.