Ci-dessous se trouvent deux React composants qui font presque la même chose. L'un est une fonction; l'autre est une classe. Chaque composant a un Animated.Value
avec un écouteur asynchrone qui met à jour _foo
sur le changement. Je dois pouvoir accéder à _foo
dans le composant fonctionnel comme je le fais avec this._foo
dans la composante classique.
FunctionalBar
ne devrait pas avoir _foo
dans la portée globale dans le cas où il y a plus d'un FunctionalBar
.FunctionalBar
ne peut pas avoir _foo
dans l'étendue de la fonction car _foo
est réinitialisé à chaque rendu de FunctionalBar
. _foo
ne doit pas non plus être dans l'état car le composant n'a pas besoin d'être rendu lorsque _foo
changements.ClassBar
n'a pas ce problème car il conserve _foo
initialisé sur this
pendant toute la durée de vie du composant.Comment puis-je conserver _foo
initialisé tout au long de la vie de FunctionalBar
sans le mettre dans le périmètre global?
import React from 'react';
import { Animated, View } from 'react-native';
var _foo = 0;
function FunctionalBar(props) {
const foo = new Animated.Value(0);
_onChangeFoo({ value }) {
_foo = value;
}
function showFoo() {
let anim = Animated.timing(foo, { toValue: 1, duration: 1000, useNativeDriver: true });
anim.start(() => console.log(_foo));
}
useEffect(() => {
foo.addListener(_onChangeFoo);
showFoo();
return () => foo.removeListener(_onChangeFoo);
});
return <View />;
}
import React from 'react';
import { Animated, View } from 'react-native';
class ClassBar extends React.Component {
constructor(props) {
super(props);
this.state = { foo: new Animated.Value(0) };
this._foo = 0;
this._onChangeFoo = this._onChangeFoo.bind(this);
}
componentDidMount() {
this.state.foo.addListener(this._onChangeFoo);
this.showFoo();
}
componentWillUnmount() {
this.state.foo.removeListener(this._onChangeFoo);
}
showFoo() {
let anim = Animated.timing(this.state.foo, { toValue: 1, duration: 1000, useNativeDriver: true });
anim.start(() => console.log(this._foo));
}
_onChangeFoo({ value }) {
this._foo = value;
}
render() {
return <View />;
}
}
Le crochet useRef
n'est pas seulement pour les références DOM, mais peut stocker n'importe quelle valeur modifiable que vous aimez.
Exemple
function FunctionalBar(props) {
const [foo] = useState(new Animated.Value(0));
const _foo = useRef(0);
function showFoo() {
let anim = Animated.timing(foo, { toValue: 1, duration: 1000, useNativeDriver: true });
anim.start(() => console.log(_foo.current));
}
useEffect(() => {
function _onChangeFoo({ value }) {
_foo.current = value;
}
foo.addListener(_onChangeFoo);
showFoo();
return () => foo.removeListener(_onChangeFoo);
}, []);
return <View />;
}
C'est un exemple assez inhabituel, mais si je lis bien, vous voulez simplement stocker des objets _foo
Uniques à chaque fois que le composant se monte et les détruire lors de son démontage, mais également empêcher des rediffusions supplémentaires lorsque cette valeur change.
J'ai déjà rencontré ce scénario et un objet simple (carte/hachage) devrait faire l'affaire:
let foos = {}
let fooCount = 0
function F(props) {
useEffect(() => {
let fooId = fooCount++
foos[fooId] = new Animated.Value(0)
foos[fooId].addListener(...)
return () => foos[fooId].removeListener(...)
}, []) // <-- do not rerun when called again (only when unmounted)
...render...
}
ou quelque chose à cet effet. si vous avez un exemple exécutable, vous pouvez le modifier pour qu'il corresponde mieux à votre exemple. de toute façon, la plupart des problèmes de portée sont résolus avec des primitives.