J'utilise des crochets react useEffect
et je vérifie si un objet a changé, puis je réexécute le crochet.
Mon code ressemble à ceci.
const useExample = (apiOptions) => {
const [data, updateData] = useState([]);
useEffect(() => {
const [data, updateData] = useState<any>([]);
doSomethingCool(apiOptions).then(res => {
updateData(response.data);
})
}, [apiOptions]);
return {
data
};
};
Malheureusement, il continue de fonctionner car les objets ne sont pas reconnus comme étant les mêmes.
Je crois que ce qui suit est un exemple de pourquoi.
const objA = {
method: 'GET'
}
const objB = {
method: 'GET'
}
console.log(objA === objB)
Peut-être que l'exécution de JSON.stringify(apiOptions)
fonctionne?
apiOptions
comme valeur d'étatJe ne sais pas comment vous utilisez le hook personnalisé, mais faire de apiOptions
une valeur d'état en utilisant useState
devrait fonctionner très bien. De cette façon, vous pouvez le servir à votre hook personnalisé en tant que valeur d'état comme ceci:
const [apiOptions, setApiOptions] = useState({ a: 1 })
const { data } = useExample(apiOptions)
De cette façon, cela ne changera que lorsque vous utiliserez setApiOptions
.
Exemple # 1
import { useState, useEffect } from 'react';
const useExample = (apiOptions) => {
const [data, updateData] = useState([]);
useEffect(() => {
console.log('effect triggered')
}, [apiOptions]);
return {
data
};
}
export default function App() {
const [apiOptions, setApiOptions] = useState({ a: 1 })
const { data } = useExample(apiOptions);
const [somethingElse, setSomethingElse] = useState('default state')
return <div>
<button onClick={() => { setApiOptions({ a: 1 }) }}>change apiOptions</button>
<button onClick={() => { setSomethingElse('state') }}>
change something else to force rerender
</button>
</div>;
}
Vous pouvez écrire un useEffect
profondément comparable comme décrit ici :
function deepCompareEquals(a, b){
// TODO: implement deep comparison here
// something like lodash
// return _.isEqual(a, b);
}
function useDeepCompareMemoize(value) {
const ref = useRef()
// it can be done by using useMemo as well
// but useRef is rather cleaner and easier
if (!deepCompareEquals(value, ref.current)) {
ref.current = value
}
return ref.current
}
function useDeepCompareEffect(callback, dependencies) {
useEffect(callback, useDeepCompareMemoize(dependencies))
}
Vous pouvez l'utiliser comme vous utiliseriez useEffect
.
Je viens de trouver une solution qui fonctionne pour moi.
Vous devez utiliser usePrevious()
et _.isEqual()
de Lodash. A l'intérieur de la useEffect()
, vous mettez une condition si la précédente apiOptions
est égale à la actuel apiOptions
. Si vrai, ne faites rien. Si faux updateData ().
Exemple :
const useExample = (apiOptions) => {
const myPreviousState = usePrevious(apiOptions);
const [data, updateData] = useState([]);
useEffect(() => {
if (myPreviousState && !_.isEqual(myPreviousState, apiOptions)) {
updateData(apiOptions);
}
}, [apiOptions])
}
usePrevious(value)
est un hook personnalisé qui crée un ref
avec useRef()
.
Vous pouvez le trouver dans le Official React Hook documentation .
const usePrevious = value => {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
Si vous êtes vraiment sûr que vous ne pouvez pas contrôler apiOptions
, remplacez simplement useEffect natif par https://github.com/kentcdodds/use-deep-compare-effect .