Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing non-state variables in functional components

Below are two React Components that do almost the same thing. One is a function; the other is a class. Each Component has an Animated.Value with an async listener that updates _foo on change. I need to be able to access _foo in the functional component like I do with this._foo in the classical component.

  • FunctionalBar should not have _foo in the global scope in case there are more than one FunctionalBar.
  • FunctionalBar cannot have _foo in the function scope because _foo is reinitialized every time the FunctionalBar renders. _foo also should not be in state because the component does not need to render when _foo changes.
  • ClassBar does not have this problem because it keeps _foo initialized on this throughout the entire life of the Component.

How do I keep _foo initialized throughout the life of FunctionalBar without putting it in the global scope?

Functional Implementation

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

Classical Implementation

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 />;   }  } 
like image 903
woodpav Avatar asked Nov 04 '18 23:11

woodpav


People also ask

Is functional component stateful or stateless?

A functional component is always a stateless component, but the class component can be stateless or stateful. There are many distinct names to stateful and stateless components.

Can stateless components have functions?

A stateless function component is a typical React component that is defined as a function that does not manage any state. There are no constructors needed, no classes to initialize, and no lifecycle hooks to worry about. These functions simply take props as an input and return JSX as an output.

Can functional components have states?

Conclusion. React's useState() hook makes functional components more powerful by allowing them to possess state. You can set an initial value, access the current value with an assurance it'll persist between re-renders, and update the state using a specially provided function.


2 Answers

The useRef hook is not just for DOM refs, but can store any mutable value you like.

Example

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 />; } 
like image 177
Tholle Avatar answered Sep 18 '22 18:09

Tholle


You can use useRef hook (it's the recommended way stated in docs):

  • Declaring variable: const a = useRef(5) // 5 is initial value
  • getting the value: a.current
  • setting the value: a.current = my_value
like image 43
yaya Avatar answered Sep 18 '22 18:09

yaya