如何在带有react-navigation的react-native上使用react钩子

时间:2020-05-24 09:38:58

标签: javascript reactjs react-native

这是使用react-navigation的App.js。它有两个屏幕,分别称为HomeScreen和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" component={HomeScreen} />
        <Stack.Screen name="Add" component={AddScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

这是主屏幕。 “ useState”中有一个“项目”。它通过导航添加作为道具给出。

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;

然后AddScreen接收“ items”作为route.params。
然后使用“ setItems”将自己的数据放入其中。
添加后,导航将返回带有添加了新项目的项目的HomeScreen。

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;

对我而言,效果很好。
但是我不确定这种方法是否正确,请使用react钩子从父级到子级提供和接收数据。
您可以修改我的代码吗?

2 个答案:

答案 0 :(得分:1)

您应该考虑使用React Context API https://uk.reactjs.org/docs/context.html。它专用于共享公共状态(在您的情况下为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);

然后像这样在App.js中与提供者共享屏幕之间的上下文

import {ItemsProvider} from 'ItemsState';

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

然后在每个屏幕中使用项目上下文,例如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>
  );
}

您还可以使用useReducer钩子使Redux更加类似。看看这篇文章 https://medium.com/simply/state-management-with-react-hooks-and-context-api-at-10-lines-of-code-baf6be8302c

答案 1 :(得分:0)

为了在组件之间共享数据,您可以使用 Context API 或 Redux,通过导航路由传递完整对象是一种反模式,您可以在文档中找到更多信息

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