J'essaie d'utiliser la méthode d' throttle
de lodash
dans un composant fonctionnel, par exemple:
const App = () => { const [value, setValue] = useState(0) useEffect(throttle(() => console.log(value), 1000), [value]) return ( <button onClick={() => setValue(value + 1)}>{value}</button> ) }
Étant donné que la méthode à l'intérieur de useEffect
est redéclarée à chaque rendu, l'effet de limitation ne fonctionne pas.
Quelqu'un at-il une solution simple?
17 Réponses :
Après un certain temps, je suis sûr qu'il est beaucoup plus facile de gérer les choses par vous-même avec setTimeout/clearTimeout
(et de le déplacer dans un crochet personnalisé séparé) que de travailler avec des assistants fonctionnels. La gestion ultérieure crée des défis supplémentaires juste après que nous ayons appliqué cela à useCallback
qui peut être recréé en raison du changement de dépendance, mais nous ne voulons pas réinitialiser le délai d'exécution.
réponse originale ci-dessous
vous pouvez (et probablement en avoir besoin) useRef
pour stocker la valeur entre les rendus. Tout comme il est suggéré pour les minuteries
Quelque chose comme ca
const throttled = useRef(throttle(() => console.log(value), 1000)) useEffect(throttled.current, [value])
Quant à l' useCallback
Cela peut fonctionner aussi
const throttled = useCallback(throttle(() => console.log(value), 1000), [value]);
Mais si nous essayons de recréer un rappel une fois la value
modifiée:
const throttled = useCallback(throttle(newValue => console.log(newValue), 1000), []);
nous pouvons trouver qu'il ne retarde pas l'exécution: une fois que la value
est modifiée, le rappel est immédiatement recréé et exécuté.
Je vois donc que useCallback
en cas d'exécution retardée ne fournit pas d'avantage significatif. C'est à vous.
[UPD] initialement c'était
const App = () => { const [value, setValue] = useState(0) const throttled = useRef(throttle((newValue) => console.log(newValue), 1000)) useEffect(() => throttled.current(value), [value]) return ( <button onClick={() => setValue(value + 1)}>{value}</button> ) }
mais de cette façon, throttled.current
s'est lié à la value
initiale (de 0) par la fermeture. Cela n'a donc jamais été changé, même sur les prochains rendus.
Soyez donc prudent lorsque vous useRef
fonctions dans useRef
raison de la fonction de fermeture.
useRef
devrait être la réponse mais ce code ne semble pas fonctionner. J'essaye de le réparer.
peut-être que j'ai manqué la valeur initiale de cette partie pour l'utilisation La useRef
la valeur initiale
Throttle-debounce utilise d'abord DELAY, puis CALLBACK;)
@mikes cela dépend (pour la version de lodash therer sont en leading
et trailing
options pour config que github.com/lodash/lodash/blob/master/throttle.js )
puisque nous utilisons des hooks, cela signifie qu'il peut être nécessaire de redéfinir l'effet ou le rappel à chaque fois que nous effectuons le rendu et en même temps le débouncing devrait fonctionner. donc ce n'est pas une réponse acceptable
@hossein alipour ne peut pas être plus d'accord avec vous. après presque un an depuis que j'ai répondu maintenant, je vois qu'il est préférable de contrôler les choses directement dans useEffect
avec setTimeout/clearTimeout
puis en utilisant la fonction d'assistance setTimeout/clearTimeout
rebond. Merci d'avoir soulevé cela.
Nous pouvons utiliser useRef
pour créer le callback et le conserver, mais je pense qu'il vaut mieux utiliser useCallback
même pour passer les variables nécessaires si nécessaire, ce qui sera rarement le cas. Nous pouvons utiliser setValue
pour changer la valeur dans useCallback
sans ajouter de value
au tableau de dépendances et même accéder à la valeur précédente en utilisant setValue(previous => ...)
. Si nous avons besoin d'accéder à la valeur directement sans la changer, nous pouvons la passer en argument comme vous le faites avec useRef
dans votre exemple comme useCallback(throttle((value) => { ... }, 1000), [])
.
J'ai écrit deux hooks simples ( use-throttled-effect et use-debounce-effect ) pour ce cas d'utilisation peut-être que cela sera utile pour quelqu'un d'autre à la recherche d'une solution simple.
import React, { useState } from 'react'; import useThrottledEffect from 'use-throttled-effect'; export default function Input() { const [count, setCount] = useState(0); useEffect(()=>{ const interval = setInterval(() => setCount(count=>count+1) ,100); return ()=>clearInterval(interval); },[]) useThrottledEffect(()=>{ console.log(count); }, 1000 ,[count]); return ( {count} ); }
Si vous l'utilisez dans handler, je suis assez certain que c'est la manière de le faire.
function useThrottleScroll() { const savedHandler = useRef(); function handleEvent() {} useEffect(() => { savedHandleEvent.current = handleEvent; }, []); const throttleOnScroll = useRef(throttle((event) => savedHandleEvent.current(event), 100)).current; function handleEventPersistence(event) { return throttleOnScroll(event); } return { onScroll: handleEventPersistence, }; }
J'utilise quelque chose comme ça et ça marche très bien:
let debouncer = debounce( f => f(), 1000, { leading: true }, // debounce one on leading and one on trailing ); function App(){ let [state, setState] = useState(); useEffect(() => debouncer(()=>{ // you can use state here for new state value }),[state]) return <div /> }
d'où vient debounce()
?
Cela pourrait être un petit crochet personnalisé, comme ceci:
useDebounce.js
import React, { useEffect } from 'react'; import useDebounce from '/path/to/useDebounce'; const App = (props) => { const [state, setState] = useState({title: ''}); const debouncedTitle = useDebounce(state.title, 1000); useEffect(() => { // do whatever you want with state.title/debouncedTitle }, [debouncedTitle]); return ( // ... ); } // ...
Exemple d'utilisation:
import React, { useState, useEffect } from 'react'; export default (value, timeout) => { const [state, setState] = useState(value); useEffect(() => { const handler = setTimeout(() => setState(value), timeout); return () => clearTimeout(handler); }, [value, timeout]); return state; }
Remarque: comme vous le savez probablement, useEffect
s'exécute toujours sur le rendu initial, et à cause de cela, si vous utilisez ma réponse, vous verrez probablement le rendu de votre composant s'exécuter deux fois, ne vous inquiétez pas, il vous suffit d'écrire un autre hook personnalisé. consultez mon autre réponse pour plus d'informations.
Dans mon cas, j'avais également besoin de réussir l'événement. Je suis allé avec ceci:
const MyComponent = () => { const handleScroll = useMemo(() => { const throttled = throttle(e => console.log(e.target.scrollLeft), 300); return e => { e.persist(); return throttled(e); }; }, []); return <div onScroll={handleScroll}>Content</div>; };
J'ai créé mon propre hook personnalisé appelé useDebouncedEffect
qui attendra d'effectuer un useEffect
jusqu'à ce que l'état ne soit pas mis à jour pendant la durée du délai.
Dans cet exemple, votre effet se connectera à la console après avoir arrêté de cliquer sur le bouton pendant 1 seconde.
App.jsx
import { useCallback, useEffect } from "react"; export const useDebouncedEffect = (effect, delay , deps) => { const callback = useCallback(effect, deps); useEffect(() => { const handler = setTimeout(() => { callback(); }, delay); return () => { clearTimeout(handler); }; }, [callback, delay]); }
useDebouncedEffect.js
import { useState } from "react"; import { useDebouncedEffect } from "./useDebouncedEffect"; const App = () => { const [value, setValue] = useState(0) useDebouncedEffect(() => console.log(value), 1000, [value]) return ( <button onClick={() => setValue(value + 1)}>{value}</button> ) }
useThrottle
, useDebounce
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script> <script>var { useReducer, useEffect, useState, useRef, useCallback } = React</script> <div id="root"></div>
useThrottle
( Lodash )const App = () => { const [value, setValue] = useState(0); useThrottle(() => console.log(value), 1000, [value]); return ( <div> <button onClick={() => setValue(value + 1)}>{value}</button> <p>value will be logged at most once per second.</p> </div> ); }; function useThrottle(cb, delay, additionalDeps) { const options = { leading: true, trailing: false }; // pass custom lodash options const cbRef = useRef(cb); const throttledCb = useCallback( _.throttle((...args) => cbRef.current(...args), delay, options), [delay] ); useEffect(() => { cbRef.current = cb; }); // set additionalDeps to execute effect, when other values change (not only on delay change) useEffect(throttledCb, [throttledCb, ...additionalDeps]); } ReactDOM.render(<App />, document.getElementById("root"));
const App = () => { // useEffect now is contained inside useThrottle useThrottle(() => console.log(value), 1000, [value]); // ... };
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <script>var { useReducer, useEffect, useState, useRef, useCallback } = React</script> <div id="root"></div>
useDebounce
( Lodash )const debounceImpl = (cb, delay) => { let isDebounced = null; return (...args) => { clearTimeout(isDebounced); isDebounced = setTimeout(() => cb(...args), delay); }; }; const throttleImpl = (cb, delay) => { let isThrottled = false; return (...args) => { if (isThrottled) return; isThrottled = true; cb(...args); setTimeout(() => { isThrottled = false; }, delay); }; }; const App = () => { const [value, setValue] = useState(0); const invokeThrottled = useThrottle( () => console.log("throttled", value), 1000 ); const invokeDebounced = useDebounce( () => console.log("debounced", value), 1000 ); useEffect(invokeThrottled, [value]); useEffect(invokeDebounced, [value]); return <button onClick={() => setValue(value + 1)}>{value}</button>; }; function useThrottle(cb, delay) { const cbRef = useRef(cb); useEffect(() => { cbRef.current = cb; }); return useCallback( throttleImpl((...args) => cbRef.current(...args), delay), [delay] ); } function useDebounce(cb, delay) { const cbRef = useRef(cb); useEffect(() => { cbRef.current = cb; }); return useCallback( debounceImpl((...args) => cbRef.current(...args), delay), [delay] ); } ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script> <script>var { useReducer, useEffect, useState, useRef, useCallback } = React</script> <div id="root"></div>
const App = () => { const [value, setValue] = useState(0); const invokeDebounced = useDebounce( () => console.log("debounced", value), 1000 ); useEffect(invokeDebounced, [value]); return ( <div> <button onClick={() => setValue(value + 1)}>{value}</button> <p> Logging is delayed until after 1 sec. has elapsed since the last invocation.</p> </div> ); }; function useDebounce(cb, delay) { const options = { leading: false, trailing: true }; const inputsRef = useRef(cb); const isMounted = useIsMounted(); useEffect(() => { inputsRef.current = { cb, delay }; }); return useCallback( _.debounce( (...args) => { // Don't execute callback, if (1) component in the meanwhile // has been unmounted or (2) delay has changed if (inputsRef.current.delay === delay && isMounted()) inputsRef.current.cb(...args); }, delay, options ), [delay, _.debounce] ); } function useIsMounted() { const isMountedRef = useRef(true); useEffect(() => { return () => { isMountedRef.current = false; }; }, []); return () => isMountedRef.current; } ReactDOM.render(<App />, document.getElementById("root"));
1. Vous pouvez remplacer Lodash par votre propre code d' throttle
ou debounce
- debounce
, comme:
import _ from "lodash" function useDebounce(cb, delay) { // ... const inputsRef = useRef(cb); // mutable ref like with useThrottle useEffect(() => { inputsRef.current = { cb, delay }; }); //also track cur. delay return useCallback( _.debounce((...args) => { // Debounce is an async callback. Cancel it, if in the meanwhile // (1) component has been unmounted (see isMounted in snippet) // (2) delay has changed if (inputsRef.current.delay === delay && isMounted()) inputsRef.current.cb(...args); }, delay, options ), [delay, _.debounce] ); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script> <script>var { useReducer, useEffect, useState, useRef, useCallback } = React</script> <div id="root"></div>
2. useThrottle
peut être raccourci, s'il est toujours utilisé avec useEffect
(idem pour useDebounce
):
const App = () => { const [value, setValue] = useState(0); const invokeDebounced = useThrottle( () => console.log("changed throttled value:", value), 1000 ); useEffect(invokeDebounced, [value]); return ( <div> <button onClick={() => setValue(value + 1)}>{value}</button> <p>value will be logged at most once per second.</p> </div> ); }; function useThrottle(cb, delay) { const options = { leading: true, trailing: false }; // pass custom lodash options const cbRef = useRef(cb); useEffect(() => { cbRef.current = cb; }); return useCallback( _.throttle((...args) => cbRef.current(...args), delay, options), [delay] ); } ReactDOM.render(<App />, document.getElementById("root"));
import _ from "lodash" function useThrottle(cb, delay) { const options = { leading: true, trailing: false }; // add custom lodash options const cbRef = useRef(cb); // use mutable ref to make useCallback/throttle not depend on `cb` dep useEffect(() => { cbRef.current = cb; }); return useCallback( _.throttle((...args) => cbRef.current(...args), delay, options), [delay] ); }
const App = () => { const [value, setValue] = useState(0); // called at most once per second (same API with useDebounce) const throttledCb = useThrottle(() => console.log(value), 1000); // usage with useEffect: invoke throttledCb on value change useEffect(throttledCb, [value]); // usage as event handler <button onClick={throttledCb}>log value</button> // ... other render code };
Pourquoi utiliser useEffect(() => { cbRef.current = cb; });
sans aucune dépendance? Cela signifie que nous exécutons un effet sur chaque re-rendu, alors pourquoi ne pas simplement assigner sans useEffect?
Bonne question - elle est destinée à toujours contenir le rappel le plus récent dans cbRef
. Une référence mutable peut être utilisée comme une variable d'instance pour les Hooks - voici un exemple avec setInterval
du blog Overreacted. La phase de rendu doit également être pure sans effets secondaires, par exemple pour être compatible avec le mode concurrent React. C'est pourquoi nous enveloppons l'affectation dans useEffect
.
En utilisant la fonction anti-rebond de lodash, voici ce que je fais:
<input value={value} onChange={debouncedGetUsers} />
Dans votre JSX:
import debounce from 'lodash/debounce' // The function that we want to debounce, for example the function that makes the API calls const getUsers = (event) => { // ... } // The magic! const debouncedGetUsers = useCallback(debounce(getUsers, 500), [])
Je suis assez en retard pour cela, mais voici un moyen de setState()
/** * Like React.setState, but debounces the setter. * * @param {*} initialValue - The initial value for setState(). * @param {int} delay - The debounce delay, in milliseconds. */ export const useDebouncedState = (initialValue, delay) => { const [val, setVal] = React.useState(initialValue); const timeout = React.useRef(); const debouncedSetVal = newVal => { timeout.current && clearTimeout(timeout.current); timeout.current = setTimeout(() => setVal(newVal), delay); }; React.useEffect(() => () => clearTimeout(timeout.current), []); return [val, debouncedSetVal]; };
Ceci est mon useDebounce
:
const TIMEOUT = 500; // wait 500 milliseconds; export function AppContainer(props) { const { dataId } = props; const [data, setData] = useState(null); // useDebounce( async () => { data = await loadDataFromAPI(dataId); setData(data); }, TIMEOUT, [dataId] ); // }
Et vous pouvez l'utiliser comme ceci:
export function useDebounce(callback, timeout, deps) { const timeoutId = useRef(); useEffect(() => { clearTimeout(timeoutId.current); timeoutId.current = setTimeout(callback, timeout); return () => clearTimeout(timeoutId.current); }, deps); }
J'écris un simple hook useDebounce
qui prend en compte le nettoyage, tout comme useEffect
fonctionne.
const debounceChange = useDebounce(function (e) { console.log("debounced text change: " + e.target.value); }, 500); // can't use debounceChange directly, since react using event pooling function deboucnedCallback(e) { e.persist(); debounceChange(e); } // later the jsx <input onChange={deboucnedCallback} />
l'essentiel est ici: https://gist.github.com/sophister/9cc74bb7f0509bdd6e763edbbd21ba64
et ceci est une démo en direct: https://codesandbox.io/s/react-hook-debounce-demo-mgr89?file=/src/App.js
utilisation:
import { useState, useEffect, useRef, useCallback } from "react"; export function useDebounceState<T>(initValue: T, delay: number) { const [value, setValue] = useState<T>(initValue); const timerRef = useRef(null); // reset timer when delay changes useEffect( function () { if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } }, [delay] ); const debounceSetValue = useCallback( function (val) { if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } timerRef.current = setTimeout(function () { setValue(val); }, delay); }, [delay] ); return [value, debounceSetValue]; } interface DebounceOptions { imediate?: boolean; initArgs?: any[]; } const INIT_VALUE = -1; export function useDebounce(fn, delay: number, options: DebounceOptions = {}) { const [num, setNum] = useDebounceState(INIT_VALUE, delay); // save actual arguments when fn called const callArgRef = useRef(options.initArgs || []); // save real callback function const fnRef = useRef(fn); // wrapped function const trigger = useCallback(function () { callArgRef.current = [].slice.call(arguments); setNum((prev) => { return prev + 1; }); }, []); // update real callback useEffect(function () { fnRef.current = fn; }); useEffect( function () { if (num === INIT_VALUE && !options.imediate) { // prevent init call return; } return fnRef.current.apply(null, callArgRef.current); }, [num, options.imediate] ); return trigger; }
Je voudrais rejoindre la fête avec mon entrée useState
rebond en utilisant useState
:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script> <div id="root"></div>
// import { React, useState } from 'react' // nomral import const { useState } = React // inline import const App = () => { const [t, setT] = useState(); const handleChange = ({ target: { value } }) => { clearTimeout(t) setT(setTimeout(() => console.log(value), 700)) } return ( <input onChange={handleChange} /> ) } ReactDOM.render(<App />, document.getElementById('root'))
Je ne sais pas si vous utilisez Redux ou non, probablement pas. Cependant, j'ai eu un problème similaire et je l'ai résolu avec Saga.
let throttledSort=(e) => action('THROTTLED_SORT', e.target.cellIndex);
Ce qu'il fait précisément est de limiter l'envoi de l'action SORT. Dans votre composant, vous devez utiliser THROTTLED_SORT et pas seulement TRIER
import { put, all, takeLatest } from "redux-saga/effects"; const delay = (ms) => new Promise((res) => setTimeout(res, ms)); function* throttledSort(e) { yield delay(400); yield put({ type: "SORT", payload: e.payload }); } function* watchSort() { yield takeLatest("THROTTLED_SORT", throttledSort); } export default function* rootSaga() { yield all([watchSort()]); }
Ce n'est pas précisément la réponse à votre question mais cela pourrait être utile, de toute façon (si vous pensez que c'est trop loin, veuillez ne pas sous-noter)
Voici un véritable crochet d'accélérateur. Vous pouvez utiliser dans un écran ou un composant pour toutes les fonctions que vous souhaitez contrôler, et elles partageront la même accélération. Ou vous pouvez appeler useThrottle()
plusieurs fois et avoir des manettes différentes pour des fonctions individuelles.
Utilisez comme ceci:
import { useCallback, useState } from "react"; // Throttles all callbacks on a component within the same throttle. // All callbacks passed in will share the same throttle. const THROTTLE_DURATION = 500; export default (callbacks: Array<() => any>) => { const [isWaiting, setIsWaiting] = useState(false); const throttledCallbacks = callbacks.map((callback) => { return useCallback(() => { if (!isWaiting) { callback() setIsWaiting(true) setTimeout(() => { setIsWaiting(false) }, THROTTLE_DURATION); } }, [isWaiting]); }) return throttledCallbacks; }
Et le crochet lui-même:
import useThrottle from '../hooks/useThrottle'; const [navigateToSignIn, navigateToCreateAccount] = useThrottle([ () => { navigation.navigate(NavigationRouteNames.SignIn) }, () => { navigation.navigate(NavigationRouteNames.CreateAccount) } ])
Voici un crochet simple pour annuler vos appels.
Pour utiliser le code ci-dessous, tout ce que vous avez à faire est de le déclarer comme tel
const { debounceRequest } = useDebounce(someFn);
Et puis appelez-le ainsi
import React from "react"; const useDebounce = (callbackFn: () => any, timeout: number = 500) => { const [sends, setSends] = React.useState(0); const stabilizedCallbackFn = React.useCallback(callbackFn, [callbackFn]); const debounceRequest = () => { setSends(sends + 1); }; // 1st send, 2nd send, 3rd send, 4th send ... // when the 2nd send comes, then 1st set timeout is cancelled via clearInterval // when the 3rd send comes, then 2nd set timeout is cancelled via clearInterval // process continues till timeout has passed, then stabilizedCallbackFn gets called // return () => clearInterval(id) is critical operation since _this_ is what cancels // the previous send. // *ð return () => clearInterval(id) is called for the previous send when a new send // is sent. Essentially, within the timeout all but the last send gets called. React.useEffect(() => { if (sends > 0) { const id = window.setTimeout(() => { stabilizedCallbackFn(); setSends(0); }, timeout); return () => { return window.clearInterval(id); }; } }, [stabilizedCallbackFn, sends, timeout]); return { debounceRequest, }; }; export default useDebounce;
La mise en œuvre est illustrée ci-dessous
debounceRequest();
const useDebounce = (func: any) => { const debounceFunc = useRef(null); useEffect(() => { if (func) { // @ts-ignore debounceFunc.current = debounce(func, 1000); } }, []); const debFunc = () => { if (debounceFunc.current) { return debounceFunc.current; } return func; }; return debFunc(); };
Est-ce une option pour vous de définir la fonction étranglée en dehors du composant
App
et de l'appeler simplement dans la fonctionuseEffect
?Oui, j'ai essayé et cela fonctionne, mais dans mon cas, ce n'est pas très élégant, car j'utilise des variables de composant dans la méthode de limitation.