Search code examples
reactjsreact-nativereact-context

React Native Context not updating across files and screens


I am attempting to use Context to create a global array which exists across screens. My setup includes a screen which displays the contents of the array, and a navigation button to the second screen, which contains a button to add an element to the list.

I would like the list on the first page to print an additional "Hello World" every time the add button is pressed, as well as display an initial item, "Hello World Initial." However, with the code below I have only been able to display the initial value, and my attempts at adding more have failed.

There are no errors thrown, pressing the button just doesn't appear to do anything. Here is a snack of the project: https://snack.expo.dev/@figbar/context-across-files-and-screens, and here is the code contained within it:

App.js:

import { TestList, TestListProvider } from './File1';
import * as React from 'react';
import {View, Text, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Screen2 from './Screen2';


const Stack = createStackNavigator();


function HomeScreen({ navigation }) {
   const _retrievedList = React.useContext(TestList);
  const populate = (arg:any) => {
    return arg.map((val, index) => <Text key={index}>{val.value}</Text>);
  }
  return (
    <View>
        <View>{populate(_retrievedList)}</View>
        <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Screen2')}
      />
    </View>
    
  );
}
function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Screen2" component={Screen2} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
export default App;

File1.js

import React from 'react'

const testObject = {
    value: "Hello World Initial",
};

export const TestList = React.createContext([testObject]);

export const TestListProvider = TestList.Provider;

Screen2.js

import { TestList, TestListProvider } from './File1';
import * as React from 'react';
import {View, Text, Button } from 'react-native';


export default function Screen2() {

  const testObject2 = {
      value: "Hello World",
  }
  const [_localUpdate, _setLocalUpdate] = React.useState([]);
  
  const addItem = () => {
    _setLocalUpdate([..._localUpdate, testObject2]);
  }
  return (
    <View>
        <TestListProvider value={_localUpdate}>
          <Button onPress={addItem} title="Add" color="#841584" />
        </TestListProvider>
    </View>
  );
}

Solution

  • Your context provider has to wrap all components that will be using the context value. In this example, only a single Button can consume the context - none of your own components can.

    You will want to move the provider - along with the state that carries its value - up to your root component.