1
votes

I am new in React world and I would like to know how I can share the state between two components.

I found a solution to this but I don't know if it is correct.

The solution consist on routing the state of a component as a props from parent to child and use this props to set the state of the child component. From child to parent routing the updated state as props and use useEffect to set the new state.

I write a simple code for explain better my issue.

The code works, but I'm not sure that is the correct way.

I have two screens Home and DeleteItem.

The purpose of Home screen is to render an array of items which is the state of Home component. By pressing the button I pass the state to DeleteItem Screen.

DeleteScreen should share the same state of HomeScreen. So I retrive the routed props and i set the state of DeleteScreen.

So I can delete items of array by a simple function and go back to HomeScreen and sending the update state by press DONE button .

The Home screen handle the update by useEffect.

So I would like to know if is a correct way to do that and If it is the shortest way.

import * as React from 'react'; import { Text, TextInput, View, Button,TouchableWithoutFeedback } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack';

function HomeScreen({ navigation, route }) {
 const [list, setList] = React.useState(["itm1","itm2","itm3","itm4"])

  React.useEffect(() => {
    if (route.params?.post) {
      setList(route.params?.post)
    }
  }, [route.params?.post]);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Delete item" onPress={() => 
      navigation.navigate('DeleteItem',{ prm: list })}/>
      {list.map((item, index) => (
        <Text style={{ margin: 10 }}>{item}</Text>))}
    </View>
  );
}

function DeleteItem({ navigation, route }) {

  const {prm}=route.params;
  const [list, setList] = React.useState(prm);

  function removeItem(index)  {
    const newArray = [...list];
    newArray.splice(index, 1);
    setList(newArray);
  }

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Done" onPress={() => {
      navigation.navigate('Home', { post: list });}}/>
      {list.map((item, index) => (
        <TouchableWithoutFeedback onClick={() => removeItem(index)}> 
              <Text style={{ margin: 10 }}>{item}</Text>
        </TouchableWithoutFeedback>))}
    </View>
  );
}

const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator mode="modal">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="DeleteItem" component={DeleteItem} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
2

2 Answers

0
votes

You can try React Context to pass data through the component tree instead of passing data via params using react navigator. As you are using React Hooks, you can checkout the React useContext hook.

0
votes

I was stuck in this issue also for hours. in react navigation v4 you can use screen props but in react navigation v5 use context to share state between components as stated in react navigation docs:

Due to the component based API of React Navigation 5.x, we have a much better alternative to screenProps which doesn't have these disadvantages: React Context. Using React Context, it's possible to pass data to any child component in a performant and type-safe way, and we don't need to learn a new API!

To start with React context you can follow this simple tutorial and this is the link for official docs