What is solution for constructor in functional components in react native?

Viewed 1364

Let me take you to my problem. I am making a timer functional component, I am passing startValue to component and then that component will start timer(decreasing one in second) using startValue passed through props.

const FunctionalComponent = (props: any) => {

const [timerValue, setTimerValue] = useState(props.initialValue)

console.log('Set State')

useEffect(() => {
    console.log('UseEffects called')

    setInterval(() => {
        setTimerValue(timerValue - 1)
    }, 1000)

}, [])

return <View><Text style={styles.textStyle}>{timerValue}</Text></View>

}

My render function in Parent.

render() {
    return <View style={styles.mainView}>
        <FunctionalComponent  initialValue={30} />
    </View>
}

Now, Every time react re-render parent component, FunctionalComponent gets called and resets timerValue value. I solved this problem using class component constructor, but I wonder is there any solution to do same in functional components.

class OTPTimer extends Component {

    constructor(props: any) {
        super(props)

        this.state = {
            timeLeft: props.fromStart
        }

        if (props.startTimer) {

            this.startTimer()

        }
    }

    componentDidUpdate(prevProps: any) {

        if (!prevProps.startTimer && this.props.startTimer) {
            this.startTimer()
            this.setState({
                timeLeft: this.props.fromStart
            })
        }
    }

    startTimer = () => {
        var interval = setInterval(() => {

            this.setState({
                timeLeft: this.state.timeLeft - 1
            })

            if (this.state.timeLeft === 0) {
                clearInterval(interval)

            }

        }, 1000)
    }

    render() {
        return <Text style={globalStyles.testStyleThree}>{`00:${this.state.timeLeft > 9 ? this.state.timeLeft : `0${this.state.timeLeft}`}`}</Text>
    }


}
3 Answers

This is where it makes sense to use React.memo in order to prevent re-rendering child components when their props don't change.

React.memo is a higher order component. It’s similar to React.PureComponent but for function components instead of classes.

If your function component renders the same result given the same props, you can wrap it in a call to React.memo for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.

    const FunctionalComponent = React.memo<{initialValue: number}>({initialValue}) => {
      const [timerValue, setTimerValue] = useState(initialValue)
    
      console.log('Set State')
    
      useEffect(() => {
          console.log('UseEffects called')
    
          setInterval(() => {
              setTimerValue(timerValue - 1)
          }, 1000)
    
      }, [])
    
      return <View><Text style={styles.textStyle}>{timerValue} 
 </Text></View>

    };

checkout React.memo, witch will prevent child component to re-render if it's props has not changed

const FunctionalComponent = React.memo((props: any) => { .... } )

People suggested useEffect but it will be invoked after render.

Use useMemo instead:

useMemo(() => {
  console.log('This is useMemo')
}, []);
Related