3

I got 3 pages

homepage, productList and productDetails

When going from homepage to productList I pass a route param,

navigation.navigate('productList', { showCategory: 'productListA'} )

InitialProcess when component mounted

Inside the productList page when the component is mounted. I am declaring use state like this.

const {showCateory} = route.params;
const [activeTab, setActiveTab] = useState(showCateory);

and calling api using that activeTab

useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      async function fetchData() {
        try {
          await dispatch(
            fetchProductList(
              activeTab,
            ),
          );
        } catch (err) {
          console.log(err);
        } 
      }
      fetchData();
    });

    return unsubscribe;
  }, []);

User Interaction

But I also add the button in the productList so that user can change the current active tab

<TouchableOpacity onPress={() => changeTab()}></TouchableOpacity>

const changeTab = async () => {
 await setActiveTab('productListB'),
 await dispatch(fetchProductList(activeTab)
}

Take note that right now active tab and data coming from api is different from when the component is start mounted.

Navigation Change again

When use goes from productList to productDetails. All thing is fine.

But inside the product details I am going back to productList with this. navigation.goBack().

When I am back in productList page The activeTab is change back to productListA and the data is change back to when component is mounted

Can I pass or change the route params when calling navigation.goBack()?

Kerry
  • 384
  • 3
  • 25
  • where are you calling setActiveTab ? Post full code. – Janak Nirmal Nov 16 '21 at 13:57
  • @JanakNirmal setActiveTab is user interaction. So This will call when user press a button. – Kerry Nov 24 '21 at 03:05
  • Seems like the 'focus' callback still has the activeTab value of the initial render. Can you try using useRef and setting its current value to the activeTab. Then use the ref object inside the 'focus' callback. – Muhammed B. Aydemir Nov 24 '21 at 07:38

3 Answers3

2

add activeTab in useEffect depedineces.

as docs say

The array of dependencies is not passed as arguments to the effect function. Conceptually, though, that’s what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically.

useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      async function fetchData() {
        try {
          await dispatch(
            fetchProductList(
              //this value will always updated when activeTab change
              activeTab,
            ),
          );
        } catch (err) {
          console.log(err);
        } 
      }
      fetchData();
    });

    return unsubscribe;
  }, [activeTab]); //<<<<< here

also you need to know setState() does not always immediately update the component. see here
so change this

const changeTab = async () => {
 //await setActiveTab('productListB'),
 //await dispatch(fetchProductList(activeTab)

 setActiveTab('productListB')
 dispatch(fetchProductList('productListB'))
}
Ahmed Gaber
  • 3,384
  • 2
  • 12
  • 18
0

This might be happening because route.params is still set to { showCategory: 'productListA'} when you are coming back to the screen.

If this is the case, you can fix it by Changing params object in changeTab() like

navigation.setParams({
  showCategory: 'productListB',
});

I hope this will fix your problem.

Rohit S K
  • 1,178
  • 3
  • 13
0

This happens because the callback function inside the focus listener uses the initial value of the state when the function was defined (at initial page render) . Throughout the lifespan of listener the callback function uses this stale state value.You can read more about this behaviour in this answer

Although the answer by Ahmed Gaber works in this case as the listener is cleared and redefined after each state change.Another common work-around is to use an useRef instead of useEffect.A ref is basically a recipe that provides a mutable object that can be passed by reference.

In your case you can initialise activeTab with navigation param value using useRef hook as :

const activeTab = useRef(showCateory);

and the focus listener callback function should be changed to use the Reference current value as

useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      async function fetchData() {
        try {
          await dispatch(
            fetchProductList(
              activeTab.current, //<<<<<<---------here
            ),
          );
        } catch (err) {
          console.log(err);
        } 
      }
      fetchData();
    });

    return unsubscribe;
  }, []);

and the changeTab function can directly update reference current value

const changeTab = async () => {
 setActiveTab.current = 'productListB';
 dispatch(fetchProductList('productListB'))
}
Karthik Suthan
  • 98
  • 1
  • 12