In our App we use a tab navigation and a stack navigation for each tab. We want an array of devices where we could add and delete devices. The array should be available on every tab.
This is our provider
import React from 'react'
const DevicesContext = React.createContext('')
export default DevicesContext
This is our 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>
);
}
this is our connect screen where we can add devices
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;
and this is our main screen
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;
If we add devices in our Connect screen they are getting updated there but not on the homescreen. Thanks for your help:)
to update context from nested component you must pass the methode setDevices
tha will update it.
to pass it do the following steps :
your context shoud be
import React from 'react'
const DevicesContext = React.createContext({
devices: [],
setDevices: () => {}, //methode will update context value
})
export default DevicesContext
App.js should be
//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 should be
function ConnectScreen(){
const {devices, setDevices} = useContext(DevicesContext);
//call setDevices will update context
....
}
HomeScreen.js should be
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
....
}