在功能组件中存储非状态变量



下面是两个React组件,它们几乎做着相同的事情。一个是函数;另一个是班级。每个组件都有一个Animated.Value和一个异步侦听器,该侦听器在更改时更新_foo。我需要能够访问功能组件中的_foo,就像我在经典组件中访问this._foo一样。

如果存在多个FunctionalBar,则FunctionalBar不应在全局范围中具有_foo
  • FunctionalBar不能在函数作用域中具有_foo,因为每次FunctionalBar渲染时都会重新初始化_foo_foo也不应处于状态,因为_foo更改时组件不需要渲染
  • ClassBar不存在此问题,因为它在组件的整个生命周期中保持_foothis上初始化
  • 如何在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 />;
    }
    }
    

    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 />;
    }
    

    您可以使用useRef钩子(这是文档中建议的方法(:

    • 声明变量:const a = useRef(5) // 5 is initial value
    • 获取值:a.current
    • 设置值:a.current = my_value

    为了支持Tholle的回答,这里有官方文档

    参考

    但是,useRef()不仅仅用于ref属性。它是方便地保持任何可变值与您使用的值类似类中的实例字段。

    这是因为useRef()创建了一个纯JavaScript对象。这个useRef()和创建{current: ...}对象之间的唯一区别useRef会在每个提供

    请记住,useRef不会在其内容发生更改时通知您。更改.current属性不会导致重新渲染。如果你愿意为了在React将ref附加或分离到DOM节点时运行一些代码,您可能需要使用回调ref。

    我很幸运地使用了带有析构函数的useRef钩子(+一个可选的变量别名"my"(,然后将所有值保留在my对象中,这样就不必使用多个ref或一直使用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 />;
    }
    

    这是一个非常不寻常的例子,但如果我没有记错的话,您只需要在每次组件装载时存储唯一的_foo对象,并在组件卸载时销毁它们,但也可以在该值更改时防止额外的重传程序。

    我以前遇到过这种情况,简单的对象(map/hash(应该可以做到:

    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...
    }
    

    或者类似的东西。如果你有一个可运行的例子,可以对它进行调整,使其更适合你的例子。无论哪种方式,大多数范围问题都是用基元来解决的。

    相关内容

    • 没有找到相关文章

    最新更新