Show user info in Profile bottom tab navigator after login successfully from Login screen? - react-native

I have a React Native project. My problem is that when login successfully from the Login screen, I navigate to the Home screen. Here I have a bottom navigator tab including Home and Profile. I want to show the user info in Profile but I don't know how to do it. Can anyone give me some ideas?
Here is my code
import React, {useState} from 'react';
import {
View,
StyleSheet,
Text,
Image,
ScrollView,
Dimensions,
TouchableOpacity,
TextInput,
Alert,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import Account from '../component/Account';
const {width: WIDTH} = Dimensions.get('window');
const Login = (props) => {
let [email, setEmail] = useState('');
let [password, setPassword] = useState('');
let [isFocused, setIsFocused] = useState(0);
const _onPress = (index) => {
setIsFocused(index);
};
const dangnhap = (params) => {
if (email.length == 0 || password.length == 0) {
Alert.alert('Thông Báo', 'Hãy nhập đầy đủ email và mật khẩu');
return;
}
try {
fetch('http://192.168.1.10:8080/api/auth/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json ; charset=utf-8',
},
body: JSON.stringify(params),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
if (responseJson.status == 200) {
props.navigation.push('Home', email);
props.navigation.navigate('Home');
} else {
Alert.alert('Thông báo', 'Đăng nhập thất bại');
}
});
} catch (error) {
console.log(error);
}
};
return (
<ScrollView style={{backgroundColor: 'white'}}>
<View style={styles.container}>
<Image
source={require('../assets/images/login.png')}
resizeMode="center"
style={styles.image}
/>
<Text style={styles.textTitle}>Chào mừng trở lại</Text>
<Text style={styles.textBody}>Đăng nhập vào tài khoản sẵn có</Text>
<View style={{marginTop: 10}} />
<View style={styles.inputContainer}>
<Icon
name="mail"
size={25}
color="#59B7C9"
style={styles.inputIcon}
/>
<TextInput
onChangeText={(value) => setEmail(value)}
placeholder="Email"
style={[
styles.input,
{borderColor: isFocused == 1 ? '#59B7C9' : 'black'},
]}
onFocus={() => _onPress(1)}
/>
</View>
<View style={styles.inputContainer}>
<Icon
name="lock-closed"
size={25}
color="#59B7C9"
style={styles.inputIcon}
/>
<TextInput
placeholder={'Mật khẩu'}
pass={true}
onChangeText={(value) => setPassword(value)}
style={[
styles.input,
{borderColor: isFocused == 2 ? '#59B7C9' : 'black'},
]}
secureTextEntry={true}
onFocus={() => _onPress(2)}
/>
</View>
<View style={{width: '90%'}}>
<TouchableOpacity
onPress={() => props.navigation.navigate('Forgot')}
style={([styles.textBody], {alignSelf: 'flex-end'})}>
<Text style={[styles.textBody, {color: 'blue'}]}>
Quên mật khẩu?
</Text>
</TouchableOpacity>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.buttonLogin}
onPress={() => {
const newUser = {
Email: email,
Password: password,
};
dangnhap(newUser);
}}>
<Text style={styles.buttonText}>Đăng nhập</Text>
</TouchableOpacity>
</View>
<Text style={styles.textBody}>Hoặc kết nối với</Text>
<View style={{flexDirection: 'row'}}>
<Account color="#3b5c8f" icon="facebook" title="Facebook" />
<Account color="#ec482f" icon="google" title="Google" />
</View>
<View style={{flexDirection: 'row', marginVertical: 5}}>
<Text style={styles.textBody}>Chưa có tài khoản?</Text>
<Text
style={[styles.textBody, {color: 'blue'}]}
onPress={() => props.navigation.navigate('Signup')}>
Đăng ký
</Text>
</View>
</View>
</ScrollView>
);
};

This might help
import {AsyncStorage} from 'react-native';
if (responseJson.status == 200) {
AsyncStorage.setItem('email', 'email#email.com');
props.navigation.navigate('Home');
}
Profile.js
import { AsyncStorage } from 'react-native';
export default const Profile = props => {
const [email, setEmail] = useState('');
useEffect(() => {
retrieveData();
}, []);
const retrieveData = async () => {
const email = await AsyncStorage.getItem('email');
setEmail(email);
};
render(){
return {
<View>
<Text>{email}</Text>
</View>
}
}
}

Related

react-native, conditional render does not show on state change. using react navigation setOptions here

in react native, i am using react navigation ,and when using setOptions i am setting up headerright, and onPress of headerRight, i am updating a boolean state to true, to show up the popup, but it does not showup untill i click on the screen once.
this view Media component is passed to a Flatlist as a Renderitem. does it make any problem here.
import { AntDesign, Feather, Ionicons, Octicons } from "#expo/vector-icons";
import { useNavigation } from "#react-navigation/native";
import { Video } from "expo-av";
import { LinearGradient } from "expo-linear-gradient";
import React, { useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
import {
Image,
ImageBackground,
LayoutAnimation,
Text,
TouchableOpacity,
TouchableWithoutFeedback,
View,
Alert
} from "react-native";
import Animated from "react-native-reanimated";
import { colors, radius } from "../../../../styles/variables";
import { AuthContext } from "../../../components/layout/layout";
import MemberModal from "../../../components/member-modal/member-modal";
import { DEFAULT_PROFILE, SUCCESS } from "../../../utils/constants/user-constants";
import { concatMediaData } from "../../../utils/helpers/concatQueryPages";
import { VIDEO } from "../../add-content/utils/constants";
import { useMediaListQuery } from "../../add-content/utils/hooks";
import { POST } from "../../report/utils/constants";
import DeletePostModal from "../deletePostModal";
import { likeKeyframe, styles } from "./style";
import {
downloadMediaSendRequest
} from "../utils/api";
import { LIKE, LIKED_BY, UNLIKE } from "../utils/constants";
import { useDeleteMediaQuery, useLikedListQuery, useLikeUnlikeMediaQuery } from "../utils/hooks";
import { updateImgixCDN } from "../../../utils/helpers/updateImgixCDN";
const ViewMedia = ({ media }) => {
const navigation = useNavigation()
const { authContext, state } = useContext(AuthContext);
const video = useRef(null);
const [mediaDetail, setMediaDetail] = useState(null)
const [mediaLoaded, setLoaded] = useState(false);
const [status, setStatus] = React.useState({});
const [showModal, setModal] = useState(false);
const [showDeleteModal, setDeleteModal] = useState(false);
const [showKebabModal, setKebabModal] = useState(false);
const [profileURI, setURI] = useState(null);
const [liked, setLiked] = useState(false);
const [totalLikes, setTotalLikes] = useState(0);
const [totalComments, setTotalComments] = useState(null);
const [likedBy, setLikedBy] = useState([]);
const [showMediaText, setMediaText] = useState(true);
const [showPlayPause, setPlayPauseIcon] = useState(null);
const [doubleTapCount, setDoubleTapCount] = useState(0);
const [showDoubleTapIcon, setDoubleTapIcon] = useState(false);
const {
data: likedListData,
isLoading: isLikesLoading,
status: likedStatus,
fetchStatus: likedFetchStatus,
} = useLikedListQuery({
mediaId: media?._id,
circleId: media.circleId._id,
pageParam: 1,
feature: LIKED_BY,
authToken: state.authToken,
});
// console.log(media.s3BucketObject)
const { mutateAsync: mutateDeleteMedia } = useDeleteMediaQuery(mediaDetail)
const { mutateAsync: mutateLikeUnlikedMedia } = useLikeUnlikeMediaQuery(mediaDetail)
// useEffect(() => {
// if (!mediaLoaded) {
// authContext.loading(true);
// }
// return () => {
// authContext.loading(false);
// };
// }, [mediaLoaded]);
useEffect(() => {
// setMediaDetail(state?.selectedMediaData)
setMediaDetail(media)
setTotalLikes(media.likes);
setTotalComments(media.comments);
setURI({ uri: updateImgixCDN(media?.uploadedBy?.profile, 'w=200&h=200') });
}, [state])
useEffect(() => {
navigation.setOptions({
headerLeft: () => (
<Ionicons
name="ellipsis-vertical"
size={26}
color={colors.color_white}
onPress={() => {
setKebabModal(!showKebabModal)
console.log(showKebabModal);
}}
/>
),
headerShown: showMediaText,
});
});
useEffect(() => {
if (likedStatus == SUCCESS && likedListData && likedListData.pages.length)
setLiked(!!likedListData?.pages[0]?.isLikedByUser);
}, [isLikesLoading, media]);
useEffect(() => {
if (mediaDetail) setPlayPause();
}, [status.isPlaying]);
const setPlayPause = () => {
if (mediaDetail?.mediaType == VIDEO) {
if (status.isPlaying) {
setPlayPauseIcon(
<Ionicons name="play" size={60} color={colors.color_white} />
);
setTimeout(() => setPlayPauseIcon(null), 1500);
} else {
setPlayPauseIcon(
<AntDesign name="pause" size={60} color={colors.color_white} />
);
}
}
};
const toggle = () => {
setModal(!showModal);
};
const toggleDeleteModal = () => {
setDeleteModal(!showDeleteModal);
setKebabModal(false);
};
const setLikes = async (likeFlag) => {
setLiked(likeFlag);
const args = {
mediaId: mediaDetail._id,
circleId: mediaDetail?.circleId._id,
authToken: state.authToken,
};
if (likeFlag) {
authContext.setSelectedMediaData({ ...state?.selectedMediaData, likes: totalLikes + 1 })
setTotalLikes((prevState) => prevState + 1);
mutateLikeUnlikedMedia({ ...args, feature: LIKE })
} else {
setDoubleTapCount(0)
authContext.setSelectedMediaData({ ...state?.selectedMediaData, likes: totalLikes - 1 })
setTotalLikes((prevState) => prevState - 1);
mutateLikeUnlikedMedia({ ...args, feature: UNLIKE })
}
};
const deleteMedia = async () => {
const args = {
mediaId: mediaDetail._id,
circleId: mediaDetail?.circleId._id,
authToken: state.authToken,
};
authContext.loading(true);
Alert.alert('Deleting post');
await mutateDeleteMedia(args)
navigation.navigate("AddContent");
authContext.loading(false);
};
return (
<TouchableOpacity activeOpacity={1}
onLongPress={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
setMediaText(false);
}}
onPressOut={() => setMediaText(true)}
onPress={() => {
if (showKebabModal) setKebabModal(!showKebabModal);
if (mediaDetail?.mediaType == VIDEO)
status.isPlaying
? video.current.pauseAsync()
: video.current.playAsync();
// Added Double Tap Like feature
let doubleTapTimer;
setDoubleTapCount((prevCount) => prevCount + 1)
if (doubleTapCount % 2 == 1 && !showDoubleTapIcon) {
setDoubleTapIcon(true)
if (doubleTapCount == 1 && !liked) setLikes(true)
clearTimeout(doubleTapTimer)
} else {
doubleTapTimer = setTimeout(() => {
(function () {
setDoubleTapCount(prevCount => prevCount + 1)
setDoubleTapIcon(false)
})()
}, 1000)
}
}} style={styles.media_screen}>
<>
<TouchableWithoutFeedback
>
<>
{mediaDetail?.mediaType == VIDEO ? (
<Video
ref={video}
style={styles.card}
source={{
uri: mediaDetail?.s3BucketObject,
}}
useNativeControls
isLooping
shouldPlay={true}
resizeMode={"contain"}
onReadyForDisplay={() => setLoaded(true)}
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>
) : (
<Image
source={{ uri: updateImgixCDN(mediaDetail?.s3BucketObject, '?auto=compress&w=720') }}
borderRadius={radius.border_radius_ternary}
style={styles.card}
resizeMode={"contain"}
// resizeMode={FastImage.resizeMode.contain}
onLoadEnd={() => setLoaded(true)}
/>
)}
<TouchableOpacity
activeOpacity={0.7}
style={styles.play_pause}
onPress={() => {
mediaDetail?.mediaType == VIDEO &&
(status.isPlaying
? video.current.pauseAsync()
: video.current.playAsync());
}}
>
{showPlayPause}
</TouchableOpacity>
{showDoubleTapIcon ? <Animated.View
entering={likeKeyframe} style={[styles.play_pause, styles.center_like_icon]}>
<AntDesign
name="heart"
size={60}
color={colors.color_green}
/>
</Animated.View> : null}
<LinearGradient
colors={[
colors.color_modal_black_bg,
colors.color_transparent,
colors.color_transparent,
colors.color_modal_black_bg,
]}
style={[showMediaText && styles.linearGradient]}
/>
</>
</TouchableWithoutFeedback>
{showMediaText && (
<>
{showKebabModal && (
<View style={styles.kebab}>
<TouchableOpacity
activeOpacity={0.7}
style={styles.kebab_feature}
onPress={async () => {
authContext.loading(true);
setKebabModal(false);
await downloadMediaSendRequest(
updateImgixCDN(mediaDetail?.s3BucketObject, 'auto=compress'),
mediaDetail?.mediaType
);
authContext.loading(false);
}}
>
<Feather
name="download"
size={24}
color={colors.color_blue}
/>
<Text style={[styles.feature_text, styles.download]}>
Download
</Text>
</TouchableOpacity>
{mediaDetail?.uploadedBy?._id == state?.userData?._id ? (
<>
<TouchableOpacity
activeOpacity={0.7}
style={styles.kebab_feature}
onPress={toggleDeleteModal}
>
<AntDesign
name="delete"
size={24}
color={colors.color_error}
/>
<Text style={[styles.feature_text, styles.delete]}>
Delete
</Text>
</TouchableOpacity>
</>
) : (
<TouchableOpacity
activeOpacity={0.7}
style={styles.kebab_feature}
onPress={() => {
navigation.navigate("Report", {
mediaId: mediaDetail?._id,
circleId: mediaDetail?.circleId?._id,
reportType: POST,
});
setKebabModal(false);
}}
>
<Octicons name="stop" size={24} color={colors.color_blue} />
<Text style={[styles.feature_text, styles.download]}>
Report post
</Text>
</TouchableOpacity>
)}
</View>
)}
<View style={styles.detail}>
<TouchableOpacity
activeOpacity={0.7}
style={styles.detail_top}
onPress={toggle}
>
<Image
source={profileURI || DEFAULT_PROFILE}
style={styles.profile}
/>
<Text style={styles.name}>
{mediaDetail?.uploadedBy?.name || "Earth Cups User"}
</Text>
</TouchableOpacity>
<View style={[styles.detail_bottom, styles.bottom]}>
<View style={styles.detail_bottom}>
<TouchableOpacity
activeOpacity={0.9}
style={styles.like_icon}
// taking current feature as a param after hitting the icon.
onPress={() => setLikes(!liked)}
>
{liked ? (
<Animated.View entering={likeKeyframe} exiting={likeKeyframe}>
<AntDesign
name="heart"
size={15}
color={colors.color_green}
/>
</Animated.View>
) : (
<Animated.View entering={likeKeyframe} exiting={likeKeyframe}>
<AntDesign
name="hearto"
size={15}
color={colors.color_black_500}
/>
</Animated.View>
)}
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.8}
onPress={() =>
navigation.navigate("MembersList", {
mediaDetail: mediaDetail,
circleId: mediaDetail?.circleId._id,
likePage: true,
})
}
>
<Text style={styles.name}>
{totalLikes} like{totalLikes > 1 && "s"}
</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
activeOpacity={0.8}
style={[
styles.detail_bottom,
styles.bottom_right,
styles.like_icon,
]}
onPress={() =>
navigation.navigate("Comments", {
mediaDetail: media,
circleId: media?.circleId._id,
})
}
>
<Image
source={require("../../../../assets/icons/comment.png")}
/>
<Text style={[styles.name, styles.comments]}>
{totalComments}
</Text>
</TouchableOpacity>
</View>
</View>
</>
)}
<MemberModal
toggle={toggle}
showModal={showModal}
memberDetail={mediaDetail?.uploadedBy}
/>
<DeletePostModal
toggle={toggleDeleteModal}
showModal={showDeleteModal}
deleteMedia={() => deleteMedia()}
/>
</>
</TouchableOpacity>
);
};
export default React.memo(ViewMedia);

React Native Drawer Navigation not showing on each page

I am very new to React Native and this is the reason why I need your help now. I try to create an app with a normal Sidemenu (Burgermenu) which should apear on ech page. And I have a Bottom tab bar which should appear on 3 pages. The problem is, that on those 3 pages the Sidemenu is not displayed. What am I doing wrong?
This is the first called Page:
import * as React from 'react';
import DrawerNavigator from './DrawerNavigator'
function App() {
return (
<DrawerNavigator />
);
}
export default App;
This is the Sidemenu (DrawerNavigator.js):
import * as React from 'react'
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '#react-navigation/drawer'
import ProjekteStackNavigator from './side_menu/Projekte'
import DashboardStackNavigator from './side_menu/Desktop'
...
import { Text, View, StyleSheet} from 'react-native';
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon(
require('../../assets/icomoon/selection.json'),
'IcoMoon',
'zepra_icons.ttf'
);
//#############################################################
const Drawer = createDrawerNavigator()
function myLogout(){
navigation.navigate("LoginScreen");
}
const DrawerNavigator = () => {
const [fontsLoaded] = useFonts({ IcoMoon: require('../../assets/icomoon/zepra_icons.ttf') });
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<Drawer.Navigator initialRouteName="Home" drawerContent={props => {
return (
<DrawerContentScrollView {...props} scrollIndicatorInsets={{ right: 1 }}>
<DrawerItemList {...props} />
<DrawerItem label="Logout" labelStyle={{marginLeft:-18, fontSize: 15,}}
icon={({ focused, color, size }) => <Icon2 style={{marginLeft:8}} color={focused ? '#1585b5' : '#6cbabf'} size={26} name={focused ? 'log-out-outline' : 'log-out-outline'} /> }
onPress={() => props.navigation.navigate("StartScreen") } />
</DrawerContentScrollView>
)
}}>
<Drawer.Screen name="Dashboard" component={DashboardStackNavigator}
options={{
drawerLabel: 'Dashboard',
drawerLabelStyle:{ marginLeft:-20, fontSize: 15},
drawerIcon: ({focused, size}) => (
<Icon name='HAUS_3' size={35} color={focused ? '#1585b5' : '#6cbabf'} />
)}}/>
<Drawer.Screen name="Projekte" component={ProjekteStackNavigator}
options={{
drawerLabel: 'Projekte',
drawerLabelStyle:{marginLeft:-20, fontSize: 15},
drawerIcon: ({focused, size}) => (
<Icon name='PROJEKTE_ALLE' size={35} color={focused ? '#1585b5' : '#6cbabf'} />
)}}/>
</Drawer.Navigator>
)
}
export default DrawerNavigator
This is the Projects Page which calls the Pages with the Bottom Tab:
import React, { useState, useEffect } from 'react';
import {Alert, View, Text, Modal, StyleSheet, Pressable, ListView, FlatList, TouchableOpacity } from 'react-native'
import { createStackNavigator } from '#react-navigation/stack'
import { theme } from '../../core/theme';
import clientConfig from '../../../client-config';
import Icon2 from 'react-native-vector-icons/Ionicons';
import ProjektOverview from '../ProjektOverview'
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon(
require('../../../assets/icomoon/selection.json'),
'IcoMoon',
'zepra_icons.ttf'
);
//#############################################################
const Stack = createStackNavigator()
const ModalComponent = ({ modalVisible, setModalVisible, children }) => {
return (
<Modal
animationType="slide"
transparent={true}
style={styles.centeredView}
visible={modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
setModalVisible(!modalVisible);
}}>
{children}
</Modal>
);
};
export default function ObjectsScreen({ navigation }){
const [modalVisible, setModalVisible] = useState(false);
const [modal2Visible, setModal2Visible] = useState(false);
const [data, setData] = React.useState(null);
const [fontsLoaded] = useFonts({ IcoMoon: require('../../../assets/icomoon/zepra_icons.ttf') });
const onClickHandler =(data)=>()=> {
navigation.navigate('ProjektOverview', {data});
};
const comp_id = localStorage.getItem('anwender_unternehmen');
if ( localStorage.getItem( 'token' )!=null ) {
React.useEffect(() => {
async function getData() {
try {
const siteUrl = clientConfig.siteUrl + '/wp-json/zep/v1/projekt-liste/' + comp_id;
const response = await fetch(siteUrl, {
method: 'GET',
headers: {
Authorization: 'Bearer '+localStorage.getItem( 'token' )
}
})
if (response.status === 200) {
let json = await response.json();
const array = json.data;
const error = array.error_code;
if(error == 0){
const projekte = array.data_values[0];
setData(projekte);
}else{
setData(1201);
}
}else {
if(response.status === 503) {
setModalVisible(true);
}
if(response.status === 403) {
setModal2Visible(true);
}
throw new Error(`failed due to status code ${response.status}`);
}
} catch (err) {
console.log(err);
}
}
getData();
}, []);
if(data != 1201){
return (
<FlatList
data={data}
keyExtractor={(item, index) => String(index) + item.value}
renderItem={({item, index})=>(
<TouchableOpacity onPress={ onClickHandler({item}) } >
<View style={{ textAlign: 'left', borderColor:'#6cbabf', borderBottomWidth: 1, padding:10, margin:0, flexDirection: "row", alignItems: "center"}}>
<Text style={{textAlign: 'left', marginLeft:15, fontSize: 16, fontWeight: '500',}}>
{item.projekt_name} {item.projekt_nummer}</Text>
<View style={{flex:1, alignItems: "center", flexDirection: "row", justifyContent: "flex-end", marginRight:30}}>
<Icon name='PROJEKTE_BEARBEITEN' size={40} color={'#6cbabf'} />
<Icon2 name='eye-outline' size={10} color={'#6cbabf'} style={{padding:-100, margin:-17, bottom:-7.5}} />
</View>
</View>
</TouchableOpacity>
)}/>
); // return
}else{
return (
<View style={{borderColor:'#6cbabf',borderWidth: 1,borderRadius:5, padding:15,margin:12,}}>
<View style={{justiftyContent:"center", alignItems:"center"}}>
<Icon name='PROJEKTE_ALLE' size={100} color={'#6cbabf'} />
</View>
<Text style={{textAlign: 'left', fontSize: 16, fontWeight: '700', paddingBottm:15,}}>Sie haben noch keine Projekte erstellt.</Text>
<Text style={{fontSize: 12}}> </Text>
<Text style={{textAlign: 'center', fontSize: 13}}>Projekte können nur in der Desktopanwendung verwalten werden.</Text>
</View>
); // return
}
}else{
navigation.navigate('Dashboard');
}
return (
<>
<ModalComponent
modalVisible={modalVisible}
setModalVisible={(val) => {
setModalVisible(val);
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Fehler 503</Text>
<Text style={styles.modalText}>Ein unbekannter Fehler ist aufgetreten!.</Text>
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModalVisible(!modalVisible)}>
<Text style={styles.textStyle}>Ok</Text>
</Pressable>
</View>
</View>
</ModalComponent>
<ModalComponent
modalVisible={modal2Visible}
setModalVisible={(val) => {
setModal2Visible(val);
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Fehler 403</Text>
<Text style={styles.modalText}>Bitte loggen Sie sich erneut ein!</Text>
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModal2Visible(!modal2Visible)}>
<Text style={styles.textStyle}>Ok</Text>
</Pressable>
</View>
</View>
</ModalComponent>
</>
);
}
This is the Bottom Navigator:
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon(
require('../../assets/icomoon/selection.json'),
'IcoMoon',
'zepra_icons.ttf'
);
//#############################################################
//##################### Seiten importieren #####################
import ProjectsScreen from './ProjectScreen';
import WaermeschutzScreen from './tabs/waermeschutz';
import BegehungenScreen from './tabs/begehungen';
//##############################################################
//##################### Menünamen für Buttontab ################
const projectsName = "Projekte";
const waermeschutzName = "Wärmeschutz";
const begehungenName = "Begehungen";
//##############################################################
//#################### BUTTON-TAB erstellen #####################
const Tab = createBottomTabNavigator();
function MainContainer() {
// Load the icon font before using it
const [fontsLoaded] = useFonts({ IcoMoon: require('../../assets/icomoon/zepra_icons.ttf') });
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<Tab.Navigator
initialRouteName={projectsName}
screenOptions={({ route }) => ({
headerShown: false,
tabBarIcon: ({ focused, color, size }) => {
let iconName;
let rn = route.name;
if (rn === projectsName) {
iconName = focused ? 'PROJEKTE_ALLE' : 'PROJEKTE_ALLE';
} else if (rn === waermeschutzName) {
iconName = focused ? 'HAUS_3' : 'HAUS_3';
} else if (rn === begehungenName) {
iconName = focused ? 'NOTIZ_ERSTELLEN' : 'NOTIZ_ERSTELLEN';
}
// You can return any component that you like here!
return <Icon name={iconName} size={43} color={color} />;
},
'tabBarActiveTintColor': '#4283b1',
'tabBarInactiveTintColor': '#5db8bd',
'tabBarStyle':{ 'paddingTop':4, 'height':90 },
'tabBarLabelStyle':{ 'paddingTop':3, 'fontSize':13 }
})}>
<Tab.Screen name={projectsName} component={ProjectsScreen} />
<Tab.Screen name={waermeschutzName} component={WaermeschutzScreen} />
<Tab.Screen name={begehungenName} component={BegehungenScreen} />
</Tab.Navigator>
);
}
export default MainContainer;
And this is the page with the ProjectsScreen:
import React, { useState, useEffect } from 'react';
import {Alert, View, Text, Modal, StyleSheet, ImageBackground, ScrollView, FlatList , TouchableOpacity, Linking} from 'react-native';
import Background from '../components/Background_2';
import BackButton from '../components/BackButton';
import helpers from '../components/Data_funks';
import Icon2 from 'react-native-vector-icons/Ionicons';
import DrawerNavigator from './DrawerNavigator'
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon( require('../../assets/icomoon/selection.json'), 'IcoMoon', 'zepra_icons.ttf');
const Bold = ({ children }) => <Text style={{ fontWeight: 'bold' }}>{children}</Text>
//#############################################################
//export default function ProjectsScreen({ route, navigation }) {
function ProjectsScreen({ route, navigation }) {
const data = route.params['data'];
const [projekte_data, setProjektdata] = useState([]);
const [bauherr, setBauherr] = useState([]);
const [bauleiter, setBauleiter] = useState([]);
const [projektleiter, setProjektleiter] = useState([]);
const [sachbearbeiter, setSachbearbeiter] = useState([]);
const [objekte, getObjekte] = useState([]);
// Projektdaten ########################################################################
useEffect(() => {
const init = async () => {
await helpers.get_projekt_data(data.item.projekt_id).then(result =>{
setProjektdata(result.p_data[0]);
setBauherr(result.bauherr[0]);
setBauleiter(result.bauleiter[0]);
setProjektleiter(result.projektleiter[0]);
setSachbearbeiter(result.sachbearbeiter[0]);
})
}
;
init();
},[]);
//###################################################################################
// Objektdaten ########################################################################
useEffect(() => {
const init2 = async () => {
await helpers.getObjekte(data.item.projekt_id).then(result2 =>{
getObjekte(result2[0]);
})
}
;
init2();
},[]);
//###################################################################################
const onClickHandler =(data)=>()=> {
navigation.navigate('ProjektOverview', {data});
};
console.log(objekte);
return(
<ScrollView scrollIndicatorInsets={{ right: 1 }} contentContainerStyle={{ flexGrow: 1 }}>
<Background>
<DrawerNavigator />
<View style={{paddingTop:50,}}>
<Icon name='KRAN' size={80} color={'#6cbabf'} style={{textAlign: 'center',}} />
</View>
<View style={{paddingTop:10,}}>
{ data.item.projekt_name !='Kein Titel'? <Text style={styles.HeadNameStyle}>{data.item.projekt_name}
<Text>{"\n"}</Text>
{data.item.projekt_nummer}</Text> : <Text style={styles.HeadNameStyle}>{data.item.projekt_nummer}</Text> }
</View>
<View style={styles.tabsStyle}>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauleiter['kontakte_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Bauleiter:</Bold> {bauleiter['kontakte_vorname']} {bauleiter['kontakte_vorname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauleiter['kontakte_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauherr['kontakte_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Bauherr:</Bold> {bauherr['kontakte_vorname']} {bauherr['kontakte_nachname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauherr['kontakte_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${projektleiter['anwender_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Projektleiter:</Bold> {projektleiter['anwender_vorname']} {projektleiter['anwender_nachname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${projektleiter['anwender_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${sachbearbeiter['anwender_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Sachbearbeiter:</Bold> {sachbearbeiter['anwender_vorname']} {sachbearbeiter['anwender_nachname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${sachbearbeiter['anwender_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
</View>
<View style={styles.objectHeader}>
{ objekte !=''? <Text style={styles.HeadNameStyle}>Objekte</Text>: null}
</View>
<FlatList style={styles.FlatList}
data={objekte}
scrollEnabled={false}
keyExtractor={(item, index) => String(index) + item.value}
renderItem={({item, index})=>(
<View style={styles.Container}>
<View style={styles.navBar}>
<Icon name='HAUS_3' size={110} color={'#6cbabf'} />
<View style={styles.centerContainer}>
<Text style={styles.centerText}>{item.objekt_name} </Text>
<Text style={styles.centerText}>{item.objekt_nummer} </Text>
</View>
</View>
<Text>{<Bold>Adresse:</Bold>} {item.objekt_strasse}</Text>
<Text>{' '} {item.objekt_plz}, {item.objekt_ort}</Text>
<Text>{' '}</Text>
<Text>{<Bold>Nutzung:</Bold>} {item.objekt_typ}, {<Bold>Vorhaben:</Bold>} {item.objekt_sanierungs_art}</Text>
</View>
)}/>
<Text>{''}</Text>
</Background>
</ScrollView>
)
}
export default ProjectsScreen;

React Native - TextInput does not get updated and is stuck with its initial state which is empty onSubmitEditing

The setSearchTerm does not get updated and is stuck with empty string all the time when i hit "done" on the keyboard. Any suggestions?
// React Native Bottom Navigation
// https://aboutreact.com/react-native-bottom-navigation/
import React, { useState } from 'react';
import { View, Text, SafeAreaView, Dimensions, FlatList, TouchableOpacity, TextInput } from 'react-native';
import { WebView } from 'react-native-webview';
import
MaterialCommunityIcons
from 'react-native-vector-icons/MaterialCommunityIcons';
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const SearchScreen = ({navigation}) => {
const [searchTerm, setSearchTerm] = useState('');
const [data, dataSet] = useState({})
const onSearchText = async() => {
alert(searchTerm);
dataSet({});
let txtSearch = searchTerm;
if(txtSearch.length > 0){
//alert(searchTerm);
let response = await fetch('https://xxxxxx',{
headers: {
'Accept': 'application/json, text/plain',
'Content-Type': 'application/json;charset=UTF-8'
},
method: 'POST',
body: JSON.stringify({ searchTerm: searchTerm }),
mode: 'no-cors',
})
response = await response.json();
alert(JSON.stringify(response.results));
//alert(JSON.stringify(response.results));
dataSet(response.results);
}else{
}
}
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () =>
<View style={{flexDirection:'row'}}>
<TextInput
placeholder='Search Here'
onChangeText={term => setSearchTerm(term)}
onSubmitEditing={onSearchText} style={{backgroundColor:'#B2DFDB',marginRight:20,width:windowWidth - 125, padding:5, borderRadius:5,}}/>
</View>
,
});
}, [navigation, ]);
const renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate("Display", { url: item.url, youtube: item.youtube })}>
<View style={{flexDirection:'row', marginBottom:20,padding:10,backgroundColor:'#B2DFDB',borderRadius:10,}}>
<View pointerEvents="none" style={{}}>
<WebView style={{width:200, height:130, }} source={{ uri: item.url }} />
</View>
<View style={{ marginLeft:10, }}>
<Text style={{color:'#00796B', flexWrap: 'wrap',}}>{item.source}</Text>
<View style={{flexDirection:'row', flex:1,}}>
<Text style={{color:'#000000', fontWeight:'bold', flex:1, flexWrap: 'wrap'}}>{item.title}</Text>
</View>
<Text style={{color:'#00838F', }}>{item.category}</Text>
<Text style={{color:'#00838F', }}>{item.country}</Text>
</View>
</View>
</TouchableOpacity>
);
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 , padding: 16, backgroundColor:'#E0F2F1',}}>
{
data.length > 0 ? (
<FlatList
style={{flex:1,}}
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>) : <View style={{flex:1,justifyContent:'center',alignItems:'center', }}><Text style={{color:'#80CBC4', fontSize:20, textAlign:'center'}}>Nothing found, please try and search again.</Text></View>
}
</View>
</SafeAreaView>
);
}
export default SearchScreen;
You don't currently have a value assigned to the textInput field. Adding a value of searchTerm should resolve it.
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () =>
<View style={{flexDirection:'row'}}>
<TextInput
placeholder='Search Here'
onChangeText={term => setSearchTerm(term)}
value={searchTerm}
onSubmitEditing={onSearchText} style={{backgroundColor:'#B2DFDB',marginRight:20,width:windowWidth - 125, padding:5, borderRadius:5,}}/>
</View>
,
});
}, [navigation, ]);

React Native inputText with Flatlist

I'm new to react-native. This component below should render comments posted by users, I would like to add an inputText component from react-native to allow users to post a comment, but don't know where I should place it within the code below.
import React, { useState, useEffect } from 'react';
import { useNavigation } from "#react-navigation/native";
import Icon from 'react-native-vector-icons/AntDesign';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ScrollView,
FlatList,
Button,
TextInput
} from 'react-native';
import parseDate from "../utils/parseDate";
import * as API from "../api/api"
export default function CommentList({ ride }) {
const [text, setText] = React.useState("");
const [commentsData, setComments] = useState([]);
const navigation = useNavigation();
useEffect(() => {
API.getCommentsByRideId(ride.ride_id).then((comments) => {
setComments(comments)
})
}, [ride.ride_id])
deleteComment = (comment_id) => {
// useEffect(() => {
API.deleteCommentsByCommentId(comment_id).then(() => {
const updatedComments = list.filter((item) => item.comment_id !== comment_id);
setComments(updatedComments)
})
// }, [comment_id])
}
//deletes on refresh only
addComment = (newComment, ride_id) => {
API.postCommentByRideId(newComment, ride_id).then(() => {
setComments(newComment)
})
}
return (
<FlatList
style={styles.root}
data={commentsData}
ItemSeparatorComponent={() => {
return (
<View style={styles.separator} />
)
}}
keyExtractor={(item) => {
return item.author;
}}
renderItem={(item) => {
const comment = item.item;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => navigation.navigate("UserProfile", { username: item.author })}>
{/* <Image style={styles.image} source={{ uri: comment.avatar_url }} /> */}
</TouchableOpacity>
<View style={styles.content}>
<View style={styles.contentHeader}>
<Text style={styles.name}>{comment.author}</Text>
<Text style={styles.time}>
{parseDate(comment.created_at)}
{comment.votes}
</Text>
</View>
<Text rkType='primary3 mediumLine'>{comment.body}</Text>
{/* <Text style={styles.time}> Likes: {comment.votes}</Text> */}
<TouchableOpacity onPress={() => deleteComment(comment.comment_id)}>
<Icon name="delete" size={20} color="#e33057" />
</TouchableOpacity>
</View>
</View>
);
}} />
);
}
This is the inputText I would like to add to allow users to post a comment.
<TextInput
value={text}
placeholder="write..."
onChangeText={text => setText(text)}
onSubmitEditing={() => addcomment(text, ride.ride_id)}
/>
if you want to add it at fixed position in bottom of screen you may do this
<View style={{flex : 1}}>
<Flatlist
contentContainerStyle={{paddingBottom: 50}}
.../>
<View style={{position : 'absolute', bottom : 0, width : '100%', height : 50}}>
//you input here
</View>
</View>
or if you want to add it last item of flatlist you may use ListFooterComponent
<FlatList
ListFooterComponent={<Input/>}
.../>
</FlatList>

React Native CRUD with RESTful API & Redux state management

I'm new in react native and trying to create an app with CRUD operation & RESTful API, but I'm stuck in the UPDATE/PUT, Can anyone help in this matter?? Below are my frontend + backend codes:
Backend side
// update data by id
router.put('/:id', validate, (req, res) => {
const bookId = req.params.id
const errors = validationResult(req)
if(!errors.isEmpty()){
return res.status(422).send({errors: errors.array()})
}
Book.findById(bookId)
.then(book => {
book.bookTitle = req.body.bookTitle,
book.ImgURL = req.body.ImgURL,
book.bookDescription = req.body.bookDescription,
book.bookAuthor = req.body.bookAuthor,
book.bookPrice = req.body.bookPrice,
book.bookTypes = req.body.bookTypes,
book.bookYear = req.body.bookYear,
book.bookRating = req.body.bookRating,
book.bookPages = req.body.bookPages
return book.save()
})
.then(result => res.send(result))
.catch(errors => console.log(errors))
})
Result in POSTMAN, I changed title from how to brew -> how to brew like professional
ReduxAction.js
export const editBook = ({id, bookTitle, ImgURL, bookDescription, bookAuthor, bookPrice, bookTypes, bookYear, bookRating, bookPages}) => {
return async dispatch => {
const response = await fetch(`http://localhost:3000/api/books/${id}`, {
method: 'PUT',
body: JSON.stringify({id, bookTitle, ImgURL, bookDescription, bookAuthor, bookPrice, bookTypes, bookYear, bookRating, bookPages})
})
const responseData = await response.json()
dispatch({
type: EDIT_BOOKS,
payload: responseData
})
}
}
EditScreen.js
import React, {useState, useEffect} from 'react'
import { StyleSheet, Text, View, ScrollView, TextInput, Button, KeyboardAvoidingView, Alert,
ActivityIndicator } from 'react-native'
import { useDispatch, useSelector } from 'react-redux'
import * as bookAction from '../redux/actions/bookAction'
import { Formik } from 'formik'
import * as Yup from 'yup'
import DropDownPicker from 'react-native-dropdown-picker'
const formSchema = Yup.object({
bookTitle: Yup.string().required('*required').min(5, '*must be between 5 to 50 characters').max(50, '*must be between 5 to 50 characters'),
ImgURL: Yup.string().required('*required'),
bookDescription: Yup.string().required('*required').min(30, '*must be at least 30 characters'),
bookAuthor: Yup.string().required('*required'),
bookPrice: Yup.number().required('*required'),
bookTypes: Yup.string().required('*required'),
bookYear: Yup.number().required('*required'),
bookRating: Yup.number().required('*required'),
bookPages: Yup.number().required('*required')
})
const AddBookScreen = props => {
const {id} = props.route.params
const book = useSelector(state => state.book.books.find(book => book._id === id))
const [isLoading, setIsLoading] = useState(false)
if(isLoading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" />
</View>
)
}
const dispatch = useDispatch()
return (
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={100}
style={{flex: 1}}>
<ScrollView>
<Formik
initialValues={{
id: id,
bookTitle: book.bookTitle,
ImgURL: book.ImgURL,
bookDescription: book.bookDescription,
bookAuthor: book.bookAuthor,
bookPrice: book.bookPrice.toString(),
bookTypes: book.bookTypes,
bookYear: book.bookYear.toString(),
bookRating: book.bookRating.toString(),
bookPages: book.bookPages.toString()
}}
validationSchema={formSchema}
onSubmit={(values) => {
console.log(values)
setIsLoading(true)
dispatch(bookAction.editBook(values))
.then(() => {
setIsLoading(false)
Alert.alert('book edited successfrully')
})
.catch(() => {
setIsLoading(false)
Alert.alert('an error occurred, please try again!')
})
}}>
{(props) =>
(
<View style={styles.form}>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Title</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookTitle')}
onBlur={props.handleBlur('bookTitle')}
value={props.values.bookTitle}
/>
<Text style={styles.error}>{props.touched.bookTitle && props.errors.bookTitle}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Imgae URL</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('ImgURL')}
onBlur={props.handleBlur('ImgURL')}
value={props.values.ImgURL}
/>
<Text style={styles.error}>{props.touched.ImgURL && props.errors.ImgURL}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Description</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookDescription')}
onBlur={props.handleBlur('bookDescription')}
value={props.values.bookDescription}
/>
<Text style={styles.error}>{props.touched.bookDescription && props.errors.bookDescription}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Author</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookAuthor')}
onBlur={props.handleBlur('bookAuthor')}
value={props.values.bookAuthor}
/>
<Text style={styles.error}>{props.touched.bookAuthor && props.errors.bookAuthor}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Price</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookPrice')}
onBlur={props.handleBlur('bookPrice')}
value={props.values.bookPrice}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookPrice && props.errors.bookPrice}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Types</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookTypes')}
onBlur={props.handleBlur('bookTypes')}
value={props.values.bookTypes}
/>
<Text style={styles.error}>{props.touched.bookTypes && props.errors.bookTypes}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Year</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookYear')}
onBlur={props.handleBlur('bookYear')}
value={props.values.bookYear}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookYear && props.errors.bookYear}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Rating</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookRating')}
onBlur={props.handleBlur('bookRating')}
value={props.values.bookRating}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookRating && props.errors.bookRating}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Pages</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookPages')}
onBlur={props.handleBlur('bookPages')}
value={props.values.bookPages}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookPages && props.errors.bookPages}</Text>
</View>
<View style={styles.buttonContainer}>
<Button title='save edit' onPress={props.handleSubmit} color='steelblue' />
</View>
</View>
)}
</Formik>
</ScrollView>
</KeyboardAvoidingView>
)
}
export default AddBookScreen
const styles = StyleSheet.create({
form: {
backgroundColor: "#ffffff",
padding: 20,
borderRadius: 10,
},
formGroup: {
width: "100%",
},
label: {
marginVertical: 10,
},
input: {
paddingHorizontal: 2,
paddingVertical: 8,
borderBottomColor: "#ccc",
borderBottomWidth: 1,
},
buttonContainer: {
marginTop: 20,
},
error: {
color: 'red'
},
centered: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
React Native Debugger
Edited
Manage to fix the error in debugger, by modifying the ReduxReducer.js
case EDIT_BOOKS:
return {
...state,
books: state.books.map(book => action.payload.find(item => item.id === book._id) || book)
}
The error is gone, but it didn't update the data
So I found the solution of my issue by Editing the ReduxReducer.js to
case EDIT_BOOKS:
return {
...state,
books: [...state.books]
}