Хранение переменных состояния в функциональных компонентах - PullRequest
0 голосов
/ 05 ноября 2018

Ниже приведены два компонента React, которые почти делают то же самое. Один - это функция; другой класс. Каждый компонент имеет Animated.Value с асинхронным прослушивателем, который обновляет _foo при изменении. Мне нужно иметь доступ к _foo в функциональном компоненте, как я делаю с this._foo в классическом компоненте.

  • FunctionalBar не должно иметь _foo в глобальной области видимости, если существует более одного FunctionalBar.
  • FunctionalBar не может иметь _foo в области действия функции, потому что _foo переинициализируется каждый раз, когда FunctionalBar рендерится. _foo также не должен находиться в состоянии, поскольку компонент не должен отображаться при изменении _foo.
  • ClassBar не имеет этой проблемы, потому что он _foo инициализируется на this в течение всего срока службы Компонента.

Как сохранить инициализацию _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 />;
  }

}

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Хук 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 />;
}
0 голосов
/ 05 ноября 2018

Это довольно необычный пример, но если я читаю это правильно, вы просто хотите хранить уникальные _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...
}

или что-то на этот счет. если у вас есть работающий пример, вы можете настроить его так, чтобы он лучше подходил вашему примеру. В любом случае, большинство проблем с областью видимости решается примитивами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...