'How to fix TypeError: navigation.setOptions is not a function

I'm trying to implement react native test library with jest to my app.

For now I have a problem with the navigation on my component.

When I'm running the test, I've got an error :

TypeError: navigation.setOptions is not a function

Here is my component:

const initialState: StateTypes = {
  toShowAsGridLayout: false,
  isLoadingMoreContacts: false
};

export const Main: FC<Props> = ({ navigation }) => {
  const dispatch = useDispatch();
  const { data } = useSelector((state: RootState) => state.appReducer);

  const [state, setState] = useState<StateTypes>(initialState);

  useLayoutEffect(() => {
    navigation.setOptions({
      title: state.isLoadingMoreContacts ? strings.LOADING : strings.ALL_CONTACTS + ' - ' + data.length,
      headerRight: () => (
        <TouchableOpacity style={styles.changeLayoutButton} onPress={changeLayout}>
          <Text style={styles.changeLayoutText}>{state.toShowAsGridLayout ? strings.LIST : strings.GRID}</Text>
        </TouchableOpacity>
      )
    });
  }, [state.isLoadingMoreContacts, state.toShowAsGridLayout])

  return (
    <View style={styles.container}>
      {renderLayout()}
    </View>
  );
};

Here is a router:

const SplashStack = createStackNavigator();
const MainStack = createStackNavigator();

export const RootNavigator = () => {
  const { isDataLoading } = useSelector((state: RootState) => state.appReducer);

  return (
    isDataLoading
      ? <SplashStack.Navigator>
        <SplashStack.Screen name={'SplashStack'} component={Splash} />
      </SplashStack.Navigator>
      : <MainStack.Navigator>
        <MainStack.Screen name={'Main'} component={Main} />
        <MainStack.Screen name={'ContactDetails'} component={ContactDetails} />
      </MainStack.Navigator>
  );
};

And a test itself:

import React from 'react';

import { render } from '@testing-library/react-native';
import { Main } from '../Main';
import * as redux from 'react-redux';
import strings from '../../constants/strings';
import mocks from '../../mocks';

describe('dispatch mock', () => {
  it('should dispatch mock', () => {
    const useDispatchSpy = jest.spyOn(redux, 'useDispatch');
    const useSelectorSpy = jest.spyOn(redux, 'useSelector');
    const mockDispatchFn = jest.fn();
    useDispatchSpy.mockReturnValue(mockDispatchFn);
    useSelectorSpy.mockReturnValue({ data: mocks });

    const { getByText } = render(<Main navigation={({})} />);
    getByText(strings.ALL_CONTACTS);
  });
});

How can i fix this error ? What should I pass to navigation props in line :

const { getByText } = render(<Main navigation={({})} />);


Solution 1:[1]

You need to pass object with setOptions method.

const { getByText } = render(<Main navigation={
  {
    setOptions: (props: { title: string, headerRight: React.FC }) => void
  }
} />);

This answer might be relevant

Solution 2:[2]

For my purpose solution was very easy, I just added ?. at the end of setOptions

useLayoutEffect(() => {
    navigation.setOptions?.({ // <--- CHANGED HERE 

      title: state.isLoadingMoreContacts ? strings.LOADING : strings.ALL_CONTACTS + ' - ' + data.length,
      headerRight: () => (
        <TouchableOpacity style={styles.changeLayoutButton} onPress={changeLayout}>
          <Text style={styles.changeLayoutText}>{state.toShowAsGridLayout ? strings.LIST : strings.GRID}</Text>
        </TouchableOpacity>
      )
    });
  }, [state.isLoadingMoreContacts, state.toShowAsGridLayout])

Solution 3:[3]

The model has several issues, so the question cannot be solved. There are however some obvious mistakes. Solving them may help for a next iteration:

  1. The order of derivatives in the initials mus exactly match the order in the list returned by the model, see documentation of package lsoda.
  2. N is obviously the total number, not a derivative. Therefore, it has no initial value and needs to be returned as second argument from the model, i.e. after the parentheses of the states vector (see documentation). Finally, it needs to be calculated before the state equations.
  3. To develop a model, always start with a simple version and then build the model up step by step. Run the model without an optimizer first and test the optimizer with a simpler example. Put the pieces together after all building blocks work.
  4. The scales of the state variables are very different and especially dW and dFD are very big. In such a case it is necessary to adapt the integration tolerances or, much easier, to rescale variables. However, I assume that the inconsistencies result from an error of units.
  5. The aim of parts of the model remain unclear. What are the state variables W and FD? Where was the model taken from? Please add some explanation how the model is motivated.

The following model corrects issues (1) and (2) and shows how to test the model before putting it into the optimizer.

library("deSolve")

# SEIARWF differential equation
SEIARWF <- function(t, state, parameters) {
  # cat(state, "\n") # enable this for debugging
  with(as.list(c(state, parameters)), {
    N <- S + E + I + A + R
    
    dS <- 0.001048*N+0.00595*R-(aH*(1+bH*cos(2*pi*t/12)))*S*(I+A)/N-
      (aW*(1+bW*cos(2*pi*t/12)))*S*W/N-
      (aF*(1+bF*cos(2*pi*t/12)))*S*FD/N-0.000582*S
    dE <- (aH*(1+bH*cos(2*pi*t/12)))*S*(I+A)/N+
      (aW*(1+bW*cos(2*pi*t/12)))*S*W/N+
      (aF*(1+bF*cos(2*pi*t/12)))*S*FD/N-
      0.75*E-0.000582*E
    dI <- 0.1*0.75*E-1*I-0.000582*I
    dA <- 0.9*0.75*E-1*A-0.000582*A
    dR <- 1*I+1*A-0.00595*R-0.000582*R
    dW <- 3014000000000 * I + 1507000000000 * A - 1.3333 * W
    dFD <- 3014000000000 * I + 1507000000000 * A - 1.3333 * FD

    list(c(dS, dE, dI, dA, dR, dW, dFD), N = N) 
  })
}

# Infected <- .... # omitted for now, can be re-introduced after correcting the model

# states
# N0 <- 1292270000 # not needed, as N is calculated as sum of all states
I0 <- 1429 # Infected[1]                  
A0 <- I0 * 9                
E0 <- 19054                        
R0 <- 303166542                   
S0 <- N0 - E0 - I0 - A0 - R0        
W0 <- 5169000000000000
FD0 <- 11080000000000000
initials <- c(S = S0, E = E0, I = I0, A =A0, R = R0, W = W0, FD = FD0)  

parameters <- c(aH = 0.0005, bH = 0.5, aW = 0.0102, bW = 0.5, aF = 0.0429, bF = 0.5)

# time
#t <- 0:(length(Infected)-1)
t <- 0:180 # the length of Infected

SEIARWF(1, initials, parameters)

# The scales of the states are very different, 
# so we need individual tolerances for the different states.
out <- ode(y = initials, times = t, func = SEIARWF, parms = parameters, atol = c(1e6, rep(1e-6, 4), rep(1e6, 2)))

plot(out)

The plot shows that it does not solve the scaling issue (wrong measurement units), but may help to improve the model formulation. I think that it can help to think about meaning and scales of W and FD.

I would recommend to read more about the scientific background and the formulation of exponential growth. It may be found in an a good microbiology or epidemiology texbook or about ecological modelling, for example, in https://hankstevens.github.io/Primer-of-Ecology/expo.html

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3