反应导航和反应上下文

时间:2021-05-10 16:57:20

标签: javascript react-native react-navigation react-context

在我们的应用程序中,我们为每个选项卡使用标签导航和堆栈导航。我们需要一系列可以添加和删除设备的设备。该数组应该在每个选项卡上都可用。

这是我们的供应商

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;

如果我们在 Connect 屏幕中添加设备,它们会在那里更新,但不会在主屏幕上更新。 感谢您的帮助:)

1 个答案:

答案 0 :(得分:0)

要从嵌套组件更新上下文,您必须传递方法 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
    ....
}