Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setParams using useEffect and avoid getting infinty renderings?

I'm using react-navigation and I have a dynamic header, so I'm using setParams and getting it in the title.

const MyComponent = ({navigation}) => {
    useEffect(() => {
        const { setParams, state } = navigation
        const { params = {} } = state
        const { description } = params
        setParams({ headerTitle: description })
    }, [])

    return (...)
}

MyComponent.navigationOptions = ({ navigation }) => ({
    title: navigation.getParam('headerTitle')
})

The problem here is that I only want to setParams once (so I use []) but I get a warning (eslint(react-hooks/exhaustive-deps)) and says that I need to add navigation to the dependency array.

If I add navigation to the dependency array, it will become a infinty loop.

setParam updates => navigation call => setParam updates => navigation and continues...

How can I call setParam only once and avoid do it correctly accordingly to react rule of hooks?

like image 277
Vencovsky Avatar asked Jul 13 '19 12:07

Vencovsky


2 Answers

Could useRef solve this as suggested at the bottom this answer?

import React, { useRef, useEffect } from 'react';

const MyComponent = ({ navigation }) => {
  const { state } = navigation;
  const { params = {} } = state;
  const description = useRef(params.description);
  const setParams = useRef(navigation.setParams);

  useEffect(() => {
    setParams.current({ headerTitle: description.current });
  }, [description, setParams]);

  return (...);
}

MyComponent.navigationOptions = ({ navigation }) => ({
    title: navigation.getParam('headerTitle')
})

I've not tested this but it looks like it should work.

For reference here are the useRef docs.

like image 70
matthew Avatar answered Sep 17 '22 02:09

matthew


I'm a year late to the party but... as far as I can tell, when setParams is called, navigation is updated, and so the component will re-render. If navigation is part of the dependency array, the useEffect will run again too. The trick is to run setParams conditionally based on the current nav params. In your case:

    useEffect(() => {
        const { setParams, state } = navigation
        const { params = {} } = state
        const { description, headerTitle } = params
        if (description !== headerTitle) {
            setParams({ headerTitle: description })
        }
    }, [navigation])

It's a little strange though that you're updating nav params with a value that is also a nav param. It seems simpler to just directly use it:

MyComponent.navigationOptions = ({ navigation }) => ({
    title: navigation.getParam('description')
})
like image 34
Emman Avatar answered Sep 21 '22 02:09

Emman