最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use react hooks on react-native with react-navigation - Stack Overflow

programmeradmin1浏览0评论

This is App.js using react-navigation. There are two screens on it called HomeScreen and AddScreen.

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import HomeScreen from './src/HomeScreen';
import AddScreen from './src/AddScreen';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" ponent={HomeScreen} />
        <Stack.Screen name="Add" ponent={AddScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

And This is home Screen. There is a 'items' in 'useState. It is gived through Add by navigation as props.

import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Button } from 'react-native';


function HomeScreen({ navigation, route }) {
  const [items, setItems] = React.useState([]);

  React.useEffect(() => {
    if (route.params?.items) {
      // Post updated, do something with `route.params.post`
      // For example, send the post to the server
      console.log('saved');
    }
  }, [route.params?.items]);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Create post"
        onPress={() => navigation.navigate('Add', { items, setItems })}
      />
      <View>
        {items.map((item, i) => {
          return (
            <View>
              <Text>{item.itemName}</Text>
              <Text>{item.itemPrice}</Text>
            </View>
          );
        })}
      </View>
    </View>
  );
}

HomeScreen.propTypes = {
  navigation: PropTypes.object.isRequired,
};

export default HomeScreen;

And AddScreen receives 'items' as route.params.
And it use 'setItems' to push his own data in it.
After adding, navigation return to HomeScreen with items that is added with new item.

import * as React from 'react';
import PropTypes from 'prop-types';

import { View, Text, Button, TextInput } from 'react-native';

function AddScreen({ route, navigation }) {
  const { items, setItems } = route.params;
  const [itemName, setItemName] = React.useState('');
  const [itemPrice, setItemPrice] = React.useState('0');

  const addItem = () => {
    setItems([...items, { itemName, itemPrice }]);
    setItemName('');
    setItemPrice('0');
  };

  return (
    <View>
      <TextInput
        multiline
        placeholder="What's on your mind?"
        value={itemName}
        onChangeText={setItemName}
      />
      <TextInput
        multiline
        placeholder="What's on your mind?"
        value={itemPrice}
        onChangeText={setItemPrice}
      />
      <Button
        title="Done"
        onPress={() => {
          addItem();
          // Pass params back to home screen
          navigation.navigate('Home', items);
        }}
      />
    </View>
  );
}

AddScreen.propTypes = {
  navigation: PropTypes.object.isRequired,
  route: PropTypes.object.isRequired,
};

export default AddScreen;

It works well on my purpose.
But I'm not sure whether this way is correct or not using react hooks to give and receive data from parent to child.
Could you modify my code ?

This is App.js using react-navigation. There are two screens on it called HomeScreen and AddScreen.

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import HomeScreen from './src/HomeScreen';
import AddScreen from './src/AddScreen';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" ponent={HomeScreen} />
        <Stack.Screen name="Add" ponent={AddScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

And This is home Screen. There is a 'items' in 'useState. It is gived through Add by navigation as props.

import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Button } from 'react-native';


function HomeScreen({ navigation, route }) {
  const [items, setItems] = React.useState([]);

  React.useEffect(() => {
    if (route.params?.items) {
      // Post updated, do something with `route.params.post`
      // For example, send the post to the server
      console.log('saved');
    }
  }, [route.params?.items]);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Create post"
        onPress={() => navigation.navigate('Add', { items, setItems })}
      />
      <View>
        {items.map((item, i) => {
          return (
            <View>
              <Text>{item.itemName}</Text>
              <Text>{item.itemPrice}</Text>
            </View>
          );
        })}
      </View>
    </View>
  );
}

HomeScreen.propTypes = {
  navigation: PropTypes.object.isRequired,
};

export default HomeScreen;

And AddScreen receives 'items' as route.params.
And it use 'setItems' to push his own data in it.
After adding, navigation return to HomeScreen with items that is added with new item.

import * as React from 'react';
import PropTypes from 'prop-types';

import { View, Text, Button, TextInput } from 'react-native';

function AddScreen({ route, navigation }) {
  const { items, setItems } = route.params;
  const [itemName, setItemName] = React.useState('');
  const [itemPrice, setItemPrice] = React.useState('0');

  const addItem = () => {
    setItems([...items, { itemName, itemPrice }]);
    setItemName('');
    setItemPrice('0');
  };

  return (
    <View>
      <TextInput
        multiline
        placeholder="What's on your mind?"
        value={itemName}
        onChangeText={setItemName}
      />
      <TextInput
        multiline
        placeholder="What's on your mind?"
        value={itemPrice}
        onChangeText={setItemPrice}
      />
      <Button
        title="Done"
        onPress={() => {
          addItem();
          // Pass params back to home screen
          navigation.navigate('Home', items);
        }}
      />
    </View>
  );
}

AddScreen.propTypes = {
  navigation: PropTypes.object.isRequired,
  route: PropTypes.object.isRequired,
};

export default AddScreen;

It works well on my purpose.
But I'm not sure whether this way is correct or not using react hooks to give and receive data from parent to child.
Could you modify my code ?

Share Improve this question asked May 24, 2020 at 9:38 Thomas JasonThomas Jason 5682 gold badges7 silver badges18 bronze badges 3
  • You can simply create a function to addItems instead of passing the hook variables, will be less plex – Guruparan Giritharan Commented May 24, 2020 at 9:45
  • @Guruparan Giritharan Can you write your code in an answer? – Thomas Jason Commented May 24, 2020 at 11:00
  • The answer below with the context implementation is remended if you are going to access it from multiple screens – Guruparan Giritharan Commented May 24, 2020 at 12:29
Add a ment  | 

2 Answers 2

Reset to default 6

You should consider using React Context API https://uk.reactjs/docs/context.html. Its dedicated to sharing the mon state (items in your case). Here is an example: You should create a mon context for items: ItemsState.js

import React, { useState, useContext } from 'react';

const ItemsContext = React.createContext([]);

export const ItemsProvider = ({ children }) => {
  return (
    <ItemsContext.Provider value={useState([])}>
      {children}
    </ItemsContext.Provider>
  );
}

export const useItems = () => useContext(ItemsContext);

Then share the context between screens with provider in App.js like this

import {ItemsProvider} from 'ItemsState';

function App() {
  return (
   <ItemsProvider> // share the items between both screens
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" ponent={HomeScreen} />
        <Stack.Screen name="Add" ponent={AddScreen} />
      </Stack.Navigator>
    </NavigationContainer>
   </ItemsProvider>
  );
}

Then use items context in each screen like this AddScreen.js

import {useItems} from './ItemsState';

function AddScreen({ route, navigation }) {
  const [items, setItems] = useItems(); // <- using items context as global useState
  const [itemName, setItemName] = React.useState('');
  const [itemPrice, setItemPrice] = React.useState('0');

  const addItem = () => {
    setItems([...items, { itemName, itemPrice }]);
    setItemName('');
    setItemPrice('0');
  };

  return (
    <View>
      <TextInput
        multiline
        placeholder="What's on your mind?"
        value={itemName}
        onChangeText={setItemName}
      />
      <TextInput
        multiline
        placeholder="What's on your mind?"
        value={itemPrice}
        onChangeText={setItemPrice}
      />
      <Button
        title="Done"
        onPress={() => {
          addItem();
          // Pass params back to home screen
          navigation.navigate('Home', items);
        }}
      />
    </View>
  );
}

You can also use useReducer hook and make more Redux-like. Check out this article https://medium./simply/state-management-with-react-hooks-and-context-api-at-10-lines-of-code-baf6be8302c

in order to share data between ponents you can use Context API or Redux, passing full objects through navigation routes is an anti-pattern, you can find more information in the docs

https://reactnavigation/docs/params/#what-should-be-in-params

发布评论

评论列表(0)

  1. 暂无评论