以下は2つのReact機能するコンポーネントほぼ同じことです。1つは関数です;もう1つはクラスです。各コンポーネントには_Animated.Value
_があり、変更時に__foo
_を更新する非同期リスナー。クラシックコンポーネントで__foo
_を使用する場合と同様に、機能コンポーネントで_this._foo
_にアクセスできるようにする必要があります。
FunctionalBar
が複数ある場合は、FunctionalBar
のグローバルスコープに__foo
_を含めないでください。FunctionalBar
がレンダリングされるたびに__foo
_が再初期化されるため、FunctionalBar
の関数スコープに__foo
_を含めることはできません。 __foo
_が変更されたときにコンポーネントがレンダリングする必要がないため、__foo
_も状態であってはなりません。ClassBar
は、コンポーネントの存続期間を通じてthis
で__foo
_を初期化し続けるため、この問題はありません。__foo
_をグローバルスコープに入れずにFunctionalBar
の存続期間を通じて初期化しておくにはどうすればよいですか?
_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 />;
}
}
_
useRef
フックはDOM参照用だけでなく、変更可能な任意の値を格納できます。
例
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 />;
}
これはかなり珍しい例ですが、これを正しく読んでいる場合は、コンポーネントがマウントされるたびに一意の_foo
オブジェクトを格納し、マウント解除時にそれらを破棄するだけでなく、この値が変更されたときに余分な再レンダリングを防止することもできます。
以前にこのシナリオに遭遇したことがあり、単純なオブジェクト(マップ/ハッシュ)がうまくいくはずです。
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...
}
またはその効果に何か。実行可能な例がある場合は、それを調整して例に合わせてください。いずれにせよ、スコープの問題を伴うほとんどのものはプリミティブで解決されます。