反应导航和反应上下文
Posted
技术标签:
【中文标题】反应导航和反应上下文【英文标题】:React Navigation and React Context 【发布时间】:2021-08-01 02:31:22 【问题描述】:在我们的应用程序中,我们为每个标签使用标签导航和堆栈导航。我们想要一组设备,我们可以在其中添加和删除设备。该数组应该在每个选项卡上都可用。
这是我们的供应商
import React from 'react'
const DevicesContext = React.createContext('')
export default DevicesContext
这是我们的 app.js
import React, useState from 'react';
import uuid from 'react-native-uuid';
import NavigationContainer from '@react-navigation/native';
import createMaterialBottomTabNavigator from '@react-navigation/material-bottom-tabs';
import MaterialCommunityIcons from '@expo/vector-icons';
import Feather from '@expo/vector-icons';
import MaterialIcons from '@expo/vector-icons';
import HomeStackScreen from "./components/home/HomeStackScreen";
import ConnectStackScreen from "./components/connect/ConnectStackScreen";
import SettingsStackScreen from "./components/settings/SettingsStackScreen";
import DevicesContext from "./components/context/DevicesContext";
const Tab = createMaterialBottomTabNavigator();
const deleteItem = (id) =>
setDevices(prevDevice =>
return prevDevice.filter(device => device.id != id)
)
console.log(devices)
const addItem = (device) =>
setDevices(prevDevices =>
return [id: uuid.v4(), name:device, ...prevDevices];
)
function MyTabs()
return (
<Tab.Navigator
initialRouteName="Home"
activeColor="#E4E4E4"
inactiveColor="#000000"
shifting=true
labelStyle= fontSize: 12
barStyle= backgroundColor: '#8DFFBB'
>
<Tab.Screen
name="Devices"
component=ConnectStackScreen
options=
tabBarLabel: 'Geräte',
tabBarIcon: ( color ) => (
<MaterialIcons name="devices" size=24 color=color />
),
/>
<Tab.Screen
name="Home"
component=HomeStackScreen
options=
tabBarLabel: 'Home',
tabBarIcon: ( color ) => (
<MaterialCommunityIcons name="home" color=color size=26 />
),
/>
<Tab.Screen
name="Settings"
component=SettingsStackScreen
options=
tabBarLabel: 'Einstellungen',
tabBarIcon: ( color ) => (
<Feather name="settings" size=24 color=color />
),
/>
</Tab.Navigator>
);
export default function App()
const [devices, setDevices] = useState([
id: uuid.v4(), name: 'thing 1', ip: 5,
id: uuid.v4(), name: 'thing 2', ip: 2,
id: uuid.v4(), name: 'thing 3', ip: 6,
id: uuid.v4(), name: 'thing 4', ip: 10,
])
return (
<DevicesContext.Provider value=devices>
<NavigationContainer>
<MyTabs />
</NavigationContainer>
</DevicesContext.Provider>
);
这是我们可以添加设备的连接屏幕
import React, useContext, useState from 'react';
import Text, View, Button, FlatList, StyleSheet, TouchableOpacity, Image from 'react-native';
import uuid from 'react-native-uuid';
import ListItem from "../shared/ListItem";
import AddItem from "../shared/AddItem";
import DevicesContext from "../context/DevicesContext";
function ConnectScreen( navigation)
const [devices, setDevices] = useState(useContext(DevicesContext));
const deleteItem = (id) =>
setDevices(prevDevice =>
return prevDevice.filter(device => device.id != id)
)
console.log(devices)
const addItem = (device) =>
setDevices(prevDevices =>
return [id: uuid.v4(), name:device, ...prevDevices];
)
return (
<View style=padding: 10, flex: 1, justifyContent: 'center'>
<View style=styles.AddNormal>
<AddItem addItem=addItem></AddItem>
<FlatList style=styles.List data=devices renderItem=(item) => (
<ListItem item=item deleteItem=deleteItem></ListItem>
)/>
</View>
<View style=styles.AddQr>
<Image source=require('../../img/qr-code-url.png') style= width: 150, height: 150, marginBottom: 10 />
<Text style= textAlign: 'center', marginBottom: 10 >Du kannst außerdem ein Gerät durch das scannen eines Qr-Code hinzufügen</Text>
<TouchableOpacity onPress=() => navigation.navigate('QrCode')style=styles.btn>
<Text style=styles.btnText>Qr-Code scannen</Text>
</TouchableOpacity>
</View>
</View>
);
const styles = StyleSheet.create(
List:
backgroundColor: '#E4E4E4',
,
AddNormal:
padding: 10, flex: 1,
,
AddQr:
backgroundColor: '#E4E4E4',
padding: 30,
flex: 1,
marginTop: 20,
marginBottom: 20,
alignItems: 'center'
,
btn:
backgroundColor: '#8DFFBB',
padding: 9,
margin: 10,
,
btnText:
color: '#000',
fontSize: 20,
textAlign: 'center',
);
export default ConnectScreen;
这是我们的主屏幕
import React, useState, useContext, useEffect from 'react';
import Button, FlatList, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View from "react-native";
import ServerOnOffSwitch, SendMessage from "./network";
import DevicesContext from "../context/DevicesContext";
const Item = ( item, onPress, backgroundColor, textColor ) => (
<TouchableOpacity onPress=onPress style=[styles.item, backgroundColor]>
<Text style=[styles.title, textColor]>item.name</Text>
</TouchableOpacity>
);
function HomeScreen ()
const [devices, setDevices] = useState(useContext(DevicesContext));
const deleteItem = (id) =>
setDevices(prevDevice =>
return prevDevice.filter(device => device.id != id)
)
const [selectedId, setSelectedId] = useState(null);
const renderItem = ( item ) =>
const backgroundColor = item.id === selectedId ? "#b5b5b5" : "#ededed";
const color = item.id === selectedId ? 'white' : 'black';
return (
<Item
item=item
onPress=() => setSelectedId(item.id)
backgroundColor= backgroundColor
textColor= color
/>
);
;
return (
<View style=padding: 10, flex: 1, justifyContent: 'center'>
<View style=padding: 10, flex: 1>
<Text style=styles.DeviceHeader>Gerät auswählen</Text>
<FlatList
data=devices
renderItem=renderItem
keyExtractor=(item) => item.id
extraData=selectedId
/>
</View>
<View style=padding: 10, flex: 1, justifyContent: 'center', alignItems: 'center'>
<SendMessage item=selectedId></SendMessage>
<ServerOnOffSwitch></ServerOnOffSwitch>
</View>
</View>
);
const styles = StyleSheet.create(
DeviceHeader:
fontSize: 22,
paddingBottom: 10,
,
item:
padding: 10,
backgroundColor: '#f8f8f8',
borderBottomWidth: 1,
borderColor: '#eee',
,
title:
fontSize: 18,
,
);
export default HomeScreen;
如果我们在连接屏幕中添加设备,它们会在那里更新,但不会在主屏幕上。 感谢您的帮助:)
【问题讨论】:
【参考方案1】:要从嵌套组件更新上下文,您必须传递 setDevices
方法,它将更新它。
要通过它,请执行以下步骤:
你的上下文应该是
import React from 'react'
const DevicesContext = React.createContext(
devices: [],
setDevices: () => , //methode will update context value
)
export default DevicesContext
App.js 应该是
//define state
const [devices, setDevices] = React.useState([])
//define constexValue
//we will pass `devices` and also `setDevices` that will update it.
const DevicesContextValue = React.useMemo(() => ( devices, setDevices), [devices]);
return (
<DevicesContext.Provider value=DevicesContextValue>
...
</DevicesContext.Provider>
);
ConnectScreen.js 应该是
function ConnectScreen()
const devices, setDevices = useContext(DevicesContext);
//call setDevices will update context
....
HomeScreen.js 应该是
function HomeScreen ()
const devices, setDevices = useContext(DevicesContext);
//use devices from context in your flatlist and when the context update the result will show in flatlist
....
【讨论】:
非常感谢它为我们所用。我们唯一需要改变的是“const [devices, setDevices]”到“const devices, setDevices”以上是关于反应导航和反应上下文的主要内容,如果未能解决你的问题,请参考以下文章