在功能组件中存储非状态变量
Storing non-state variables in functional components
下面是两个 几乎 做同样事情的 React 组件。一个是函数;另一个是class。每个组件都有一个 Animated.Value
和一个异步侦听器,在更改时更新 _foo
。我需要能够访问功能组件中的 _foo
,就像我在 classical 组件中访问 this._foo
一样。
FunctionalBar
在全局范围内不应有 _foo
,以防有多个 FunctionalBar
。
FunctionalBar
不能在函数作用域中包含 _foo
,因为每次 FunctionalBar
渲染时都会重新初始化 _foo
。 _foo
也不应处于状态,因为当 _foo
更改时组件不需要呈现。
ClassBar
没有这个问题,因为它在组件的整个生命周期中保持 _foo
在 this
上初始化。
如何在 FunctionalBar
的整个生命周期中保持 _foo
初始化而不将其放入全局范围?
功能实现
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 />;
}
}
这是一个非常不寻常的例子,但如果我没看错的话,你只是想在每次组件安装时存储唯一的 _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...
}
或类似的东西。如果您有一个 运行nable 示例,可以调整它以使其更适合您的示例。无论哪种方式,大多数有范围问题的事情都是用原语解决的。
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 />;
}
为了支持 Tholle 的回答这里是官方文档
However, useRef()
is useful for more than the ref attribute. It’s
handy for keeping any mutable value around similar to how you’d use
instance fields in classes.
This works because useRef()
creates a plain JavaScript object. The
only difference between useRef()
and creating a {current: ...}
object
yourself is that useRef
will give you the same ref object on every
render.
Keep in mind that useRef
doesn’t notify you when its content changes.
Mutating the .current property doesn’t cause a re-render. If you want
to run some code when React attaches or detaches a ref to a DOM node,
you may want to use a callback ref instead.
您可以使用 useRef hook (it's the recommended way stated in docs):
- 声明变量:
const a = useRef(5) // 5 is initial value
- 获取值:
a.current
- 设置值:
a.current = my_value
我有幸使用 useRef
钩子解构(+ 一个可选的变量别名“my”),然后你将所有值保存在 my
对象中,这样你就不会不必使用多个引用或一直使用 myref.current
:
function MyComponent(props) {
const componentRef = useRef({});
const { current: my } = componentRef;
my.count = 42;
console.log(my.count); // 42
my.greet = "hello";
console.log(my.greet); // hello
return <div />;
}
下面是两个 几乎 做同样事情的 React 组件。一个是函数;另一个是class。每个组件都有一个 Animated.Value
和一个异步侦听器,在更改时更新 _foo
。我需要能够访问功能组件中的 _foo
,就像我在 classical 组件中访问 this._foo
一样。
FunctionalBar
在全局范围内不应有_foo
,以防有多个FunctionalBar
。FunctionalBar
不能在函数作用域中包含_foo
,因为每次FunctionalBar
渲染时都会重新初始化_foo
。_foo
也不应处于状态,因为当_foo
更改时组件不需要呈现。ClassBar
没有这个问题,因为它在组件的整个生命周期中保持_foo
在this
上初始化。
如何在 FunctionalBar
的整个生命周期中保持 _foo
初始化而不将其放入全局范围?
功能实现
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 />;
}
}
这是一个非常不寻常的例子,但如果我没看错的话,你只是想在每次组件安装时存储唯一的 _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...
}
或类似的东西。如果您有一个 运行nable 示例,可以调整它以使其更适合您的示例。无论哪种方式,大多数有范围问题的事情都是用原语解决的。
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 />;
}
为了支持 Tholle 的回答这里是官方文档
However,
useRef()
is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.This works because
useRef()
creates a plain JavaScript object. The only difference betweenuseRef()
and creating a{current: ...}
object yourself is thatuseRef
will give you the same ref object on every render.Keep in mind that
useRef
doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.
您可以使用 useRef hook (it's the recommended way stated in docs):
- 声明变量:
const a = useRef(5) // 5 is initial value
- 获取值:
a.current
- 设置值:
a.current = my_value
我有幸使用 useRef
钩子解构(+ 一个可选的变量别名“my”),然后你将所有值保存在 my
对象中,这样你就不会不必使用多个引用或一直使用 myref.current
:
function MyComponent(props) {
const componentRef = useRef({});
const { current: my } = componentRef;
my.count = 42;
console.log(my.count); // 42
my.greet = "hello";
console.log(my.greet); // hello
return <div />;
}