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

时间:2018-11-04 23:39:28

标签: javascript reactjs react-native react-hooks

下面是两个几乎做同一件事的React组件。一个是功能;另一个是功能。另一个是一类。每个组件都有一个Animated.Value和一个异步侦听器,该侦听器会在更改时更新_foo。我需要能够像使用经典组件中的_foo一样访问功能组件中的this._foo

    如果有多个FunctionalBar,则
  • _foo在全局范围内不应包含FunctionalBar
  • FunctionalBar不能在函数范围内包含_foo,因为_foo每次渲染时都会重新初始化FunctionalBar_foo也不应该处于状态,因为当_foo更改时,该组件不需要呈现。
  • ClassBar不存在此问题,因为它在组件的整个生命周期内都在_foothis进行了初始化。

如何在_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 />;
  }

}

5 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:1)

您可以使用useRef钩子(这是docs中建议的方式):

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

答案 2 :(得分:0)

这是一个非常不寻常的示例,但是,如果我正确地阅读了此示例,则只想在每次组件安装时存储唯一的_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...
}

或类似的东西。如果您有一个可运行的示例,可以对其进行调整以使其更适合您的示例。无论哪种方式,大多数具有范围问题的事物都可以通过基元来解决。

答案 3 :(得分:0)

只是为了支持Tholle,这是官方文档

Reference

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

之所以可行,是因为useRef()创建了一个纯JavaScript对象。的 useRef()与创建{current: ...}对象之间的唯一区别 你自己是useRef会在每个 渲染。

请注意,useRef的内容更改时不会通知您。 更改.current属性不会导致重新渲染。如果你想 在React将引用附加或分离到DOM节点时运行一些代码, 您可能要改用回调引用。

答案 4 :(得分:0)

我很幸运地使用 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 />;
}
相关问题