Using #react-pdf/renderer on an express js server - node.js

I have a react webapp that I'd like have to render a pdf and email it when a button is pushed. For testing sake, when the button is pushed in the react frontend, it sends a request to my expressjs backend and attempts to generate a static pdf through #react-pdf/renderer.
I don't have a clear understanding of ES Modules vs CommonJS, but my server was using CommonJS, so I added "type": "module" to the server's package.json and updated the imports in server.js. However, the compiler complains about SyntaxError: Unexpected token '<' in server.js and materials.js (depending on setup). What am I doing wrong?
(code below has been cleaned to anonymize)
Edit
Here is an example of react-pdf/renderer being used on Node
server.js:
// const express = require('express');
// const cors = require('cors');
// const fs = require('fs')
// const react = require('react')
// const reactpdf = require('#react-pdf/renderer');
// const materials = require('./pdf/src/materials');
import express from 'express';
import cors from 'cors';
import fs from 'fs';
import react from 'react';
import ReactPDF from '#react-pdf/renderer';
import MaterialsList from './materials.js';
const app = express();
const port = 5000;
app.use(cors())
app.use(express.urlencoded());
app.use(express.json());
app.listen(port, function () {
console.log(`server running on http://localhost:${port}`);
})
app.post('/sendmaterials', cors(), function (req, res) {
// const pdf = req.body;
// console.log(pdf);
// reactpdf.render(pdf, `${__dirname}/trial.pdf`);
reactpdf.render(<MaterialsList />, `${__dirname}/trial.pdf`);
// fs.writeFile('trial.pdf', pdf, (err) => {
// // throws an error, you could also catch it here
// if (err) throw err;
// // success case, the file was saved
// console.log('PDF saved!');
// });
})
package.json:
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"dependencies": {
"#react-pdf/renderer": "^1.6.13",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"firebase": "^9.0.0-beta.1",
"nodemon": "^2.0.6",
"react": "^17.0.2"
},
"devDependencies": {
"husky": "^5.1.3",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"pretty-quick": "^3.1.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "concurrently \"nodemon server.js\" \"cd frontend && yarn start\"",
"init": "concurrently \"yarn\" \"cd frontend && yarn\"",
"install-initial": "concurrently \"yarn install\" \"cd frontend && yarn install\"",
"start-frontend": "cd frontend && yarn start",
"start-server": "nodemon server.js",
"pretty-quick": "pretty-quick",
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
},
"lint-staged": {
"linters": {
"src/**/*.{js,css}": [
"prettier --write",
"git add"
]
}
}
}
materials.js:
import React from 'react';
import {
Document,
Page,
Text,
View,
StyleSheet,
Image,
// Font,
} from '#react-pdf/renderer';
import Logo from './images/img.png'
// import Trebuchet from './fonts/Trebuchet/trebuchet-ms.ttf'
// Font.register({
// family: 'Trebuchet MS',
// src: Trebuchet,
// })
// Create styles
const styles = StyleSheet.create({
page: {
padding: 30,
},
container: {
marginTop: 20,
marginBottom: 20,
flex: 0,
flexDirection: 'row',
'#media max-width: 400': {
flexDirection: 'column',
},
},
image: {
marginTop: 20,
},
mainTitle: {
// fontFamily: 'Trebuchet MS',
paddingLeft: 15,
fontWeight: 'bold',
color: "#000000",
fontSize: 19,
},
title: {
// fontFamily: 'Trebuchet MS',
fontWeight: 'bold',
color: "#000000",
fontSize: 16,
textDecoration: 'underline',
},
regGrey: {
// fontFamily: 'Trebuchet MS',
color: "#8d8d8d",
fontSize: 12,
},
regBlack: {
// fontFamily: 'Trebuchet MS',
color: "#101010",
fontSize: 12,
marginBottom: 15,
},
column: {
flexDirection: 'column',
width: 180,
paddingLeft: 15,
paddingRight: 15,
'#media max-width: 400': {
width: '100%',
paddingRight: 0,
},
'#media orientation: landscape': {
width: 200,
},
},
table: {
width: '100%',
alignContent: 'center',
borderWidth: 0,
display: 'flex',
flexDirection: 'column',
paddingTop: 10,
},
header: {
backgroundColor: "#4c4c4c",
fontWeight: 'bold',
color: "#fdfdfd",
flexWrap: 'wrap'
},
tableRow:{
display: 'flex',
flexDirection: 'row',
},
lightRow:{
display: 'flex',
flexDirection: 'row',
backgroundColor: "#cfcfcf",
},
darkRow:{
display: 'flex',
flexDirection: 'row',
backgroundColor: "#aeaeae",
},
cell: {
fontColor: "#101010",
// fontFamily: 'Trebuchet MS',
fontSize: 12,
borderWidth: 0,
display: 'flex',
justifyContent: 'center',
alignContent: 'center',
textAlign: 'center',
flexWrap: 'wrap'
},
});
// Create table object
const Table = ({header, alternate, children, col}) => (
<View style={styles.table}>
{children.map((row, ind) =>
<View key={ind} style={[styles.tableRow,
header && ind === 0 ? styles.header: {},
alternate && ind % 2 === 0 && ind !== 0 ? styles.lightRow: {},
alternate && ind % 2 !== 0 && ind !== 0 ? styles.darkRow: {},
]}>
{row.map((cell, j) =>
<View key={j} style={[styles.cell, {width:col[j], height: 40}]}>
{
typeof(cell) === 'string' || typeof(cell) === 'number' ?
<Text>{cell}</Text> : cell
}
</View>
)}
</View>
)}
</View>
)
// Create Document Component
const MaterialsList = () => (
<Document>
<Page style={styles.page}>
<View style={styles.container}>
<View style={styles.column}>
<Text style={styles.title}>
Steels
</Text>
<Table
col={['60%', '40%']}
header
alternate
children={[
['Item', 'Quantity'],
['Steel', '10'],
['U Channel', '10'],
['Gate Insert', '10'],
]} />
</View>
</View>
</Page>
</Document>
);
export default MaterialsList

The problem was in the package.json file, I was missing the babel libraries and config file. I have a example repo showing the correct setup and a link to the discussion on the react-pdf/renderer github discussion.

Related

React Native Paper - Font Family not take effect in theme

Version:
"react-native": "0.68.2",
"react-native-paper": "5.0.0-rc.3",
"react-native-vector-icons": "^9.2.0",
Problem: the fontFamily in the
<Text variant="displayLarge" theme={{ typescale: { displayLarge: { fontSize: 30, fontFamily: 'HelveticaNeue-Thin' },},}}> does not take effect while the <Text style={theme.fonts.thin}> does works as expected.
https://snack.expo.dev/#wztrustgrid/fontfamilyintheme
import { StyleSheet, View } from 'react-native';
import {
configureFonts,
Provider as PaperProvider,
MD3LightTheme as DefaultTheme,
Text,
} from 'react-native-paper';
const fontConfig = {
ios: {
thin: {
fontFamily: 'HelveticaNeue-Thin',
fontSize: 30,
},
},
};
const theme = {
...DefaultTheme,
fonts: configureFonts(fontConfig),
};
export default function App() {
return (
<PaperProvider
theme={theme}
>
<View style={styles.container}>
{/* Display correct font */}
<Text style={theme.fonts.thin}>
ABCDEFGHIJKLM NOPQRSTUVWXYZ abcdefghijklm nopqrstuvwxyz 1234567890
</Text>
{/* Display incorrect font */}
<Text
variant="displayLarge"
theme={{
typescale: {
displayLarge: { fontSize: 30, fontFamily: 'HelveticaNeue-Thin' },
},
}}
>
ABCDEFGHIJKLM NOPQRSTUVWXYZ abcdefghijklm nopqrstuvwxyz 1234567890
</Text>
</View>
</PaperProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

how to post array of multiple object in react native

**how to pass array of multiple object in database react native . i aslo tried axios fetch and redux but its not responding **
import React, { useState, useEffect, useLayoutEffect } from 'react';
import { StyleSheet, Text, View, FlatList, TouchableOpacity, ScrollView, Dimensions } from 'react-native';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import _ from "lodash"
import ClassSectionFilter from '../singleStudentAttendance/ClassSectionFilter';
import { CheckBox } from 'react-native-elements';
import { useIsFocused } from "#react-navigation/native";
import { useRegisterTechAttendanceMutation } from '../../../services/userAuthApi';
import Toast from "react-native-toast-message";
import axios from 'axios'
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const MarkAttendanceScreen = ({ navigation, route }) => {
const [columns, setColumns] = useState([
"RollNo",
"Name",
])
const [direction, setDirection] = useState('')
const [selectedColumn, setSelectedColumn] = useState('')
const [ teachers , setTeachers] = useState([]);
const [ attendance, setAttendance ] = useState()
const [ attendanceState, setAttendanceState ] = useState('')
const fetchData = async () => {
const resp = await fetch(`http://192.168.18.64:8000/api/user/getSometeacher/${route.params.schoolId}`);
const data = await resp.json();
const schAdminId = (data.map(l => l._id ? { ...l, schoolAdminID: route.params.schoolAdminID } : l));
setAttendanceState(schAdminId)
};
const focus = useIsFocused();
useLayoutEffect(()=>{
fetchData();
}, [focus])
const MarkAttendance = (item, S) => {
const attend = (attendanceState.map(l => l._id === item._id ? { ...l, attendance: S } : l));
setAttendanceState(attend)
setAttendance(attend)
}
const [items, setItems] = useState()
const sortTable = (column) => {
const newDirection = direction === "desc" ? "asc" : "desc"
const sortedData = _.orderBy(teachers, [column], [newDirection])
setSelectedColumn(column)
setDirection(newDirection)
setTeachers(sortedData)
}
const [registerTechAttendance] = useRegisterTechAttendanceMutation();
const handleFormSubmit = async () => {
const bodyFormData = new FormData();
attendance.forEach((item) => {
bodyFormData.append('attendance', item);
});
const res = axios.post('http://192.168.18.64:8000/api/user/teacherattendance', bodyFormData)
if (res.data.status === "success") {
navigation.navigate("SchoolAdminHomePage");
}
if (res.data.status === "failed") {
Toast.show({
type: "warning",
position: "top",
topOffset: 0,
text1: res.data.message,
});
}
};
// const onSubmit = () => {
// const formData = new FormData()
// formData.append(attendance);
// console.log(formData)
// fetch('http://192.168.18.64:8000/api/user/teacherattendance', {
// method: "POST",
// body: JSON.stringify(formData),
// headers: {
// 'content-type': 'application/json',
// }
// })
// .then((response) => console.log(response))
// .catch(err => {
// console.log(err);
// })
// }
const tableHeader = () => (
<View style={styles.tableHeader} >
{
columns.map((column, index) => {
{
return (
<TouchableOpacity
key={index}
style={styles.columnHeader}
onPress={() => sortTable(column)}>
<Text style={styles.columnHeaderTxt}>{column + ""}
{selectedColumn === column && <MaterialCommunityIcons
name={direction === "desc" ? "arrow-down-drop-circle" : "arrow-up-drop-circle"}
/>
}
</Text>
</TouchableOpacity>
)
}
})
}
</View>
)
return (
<View style={{ height: windowHeight, width: '100%' }}>
<View >
<ClassSectionFilter />
</View>
<FlatList
data={attendanceState}
keyExtractor={(item, index) => index + ""}
style={{ maxWidth: '100%' }}
ListHeaderComponent={tableHeader}
stickyHeaderIndices={[0]}
extraData={attendanceState}
renderItem={({ item, index }) => {
return (
<View style={{ ...styles.tableRow, backgroundColor: index % 2 == 1 ? "#F0FBFC" : "white", width: '100%', }}>
<Text style={{ ...styles.columnRowTxt, fontWeight: "bold" }}>{item.roll_no}</Text>
<Text style={{ ...styles.columnRowTxt }}>{item.first_name}</Text>
<ScrollView horizontal={true}
showsHorizontalScrollIndicator={true}
pagingEnabled={true}
style={{ width: '150%' }}
>
<View style={{ flexDirection: 'row', left: 40 }}>
<View
style={{
left: 23
}}
>
<CheckBox
title='P'
checkedColor='green'
checked={item.attendance === 'P' ? true : false}
checkedIcon="dot-circle-o"
unCheckedIcon='circle-o'
onPress={() => MarkAttendance(item, 'P')}
containerStyle={{
alignItems: 'center',
justifyContent: 'center',
height: 50,
right: 50,
alignItems: 'center',
justifyContent: 'center',
top: -10,
backgroundColor: 'transparent'
}}
/>
{/* <BouncyCheckbox
size={20}
fillColor="green"
unfillColor="#FFFFFF"
text="P"
iconStyle={{ }}
textStyle={{ }}
onPress={()=>MarkPresent()}
isChecked={false}
/> */}
</View>
<View style={{
left: 5
}}>
<CheckBox
title='A'
checkedColor='red'
checked={item.attendance === 'A' ? true : false}
checkedIcon="dot-circle-o"
unCheckedIcon='circle-o'
onPress={() => MarkAttendance(item, 'A')}
containerStyle={{
alignItems: 'center',
justifyContent: 'center',
height: 50,
right: 50,
alignItems: 'center',
justifyContent: 'center',
top: -10,
backgroundColor: 'transparent'
}}
/>
{/* <BouncyCheckbox
size={20}
fillColor="red"
unfillColor="#FFFFFF"
text="A"
iconStyle={{ }}
textStyle={{ }}
onPress={()=>MarkAbsent()}
/> */}
</View>
<View style={{
left: 5,
}}>
<CheckBox
title='L'
checkedColor='gray'
checked={item.attendance === 'L' ? true : false}
checkedIcon='dot-circle-o'
unCheckedIcon='circle-o'
onPress={() => MarkAttendance(item, 'L')}
containerStyle={{
alignItems: 'center',
justifyContent: 'center',
height: 50,
right: 70,
alignItems: 'center',
justifyContent: 'center',
top: -10,
backgroundColor: 'transparent',
}}
/>
</View>
</View>
</ScrollView>
</View>
)
}}
/>
<View>
<TouchableOpacity
onPress={handleFormSubmit}
style={{
justifyContent: "center",
alignItems: "center",
padding: 15,
width: "100%",
marginVertical: 5,
borderRadius: 50,
marginBottom: 60,
fontWeight: "bold",
backgroundColor: "#5062BD",
elevation: 1,
marginTop: 30,
bottom:20,
}}
>
<Text
style={{
color: "white",
justifyContent: "center",
alignItems: "center",
}}
>
Submit Attendance
</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
tableHeader: {
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
backgroundColor: "#5062BD",
borderTopEndRadius: 10,
borderTopStartRadius: 10,
height: 50,
},
tableRow: {
flexDirection: "row",
height: 40,
margin: 2,
left: 8
},
columnHeader: {
width: "16%",
justifyContent: "center",
alignItems: "flex-start",
margin: 10
},
columnHeaderTxt: {
color: "white",
fontWeight: "bold",
},
columnRowTxt: {
width: "18%",
}
});
export default MarkAttendanceScreen
data also show in my console but it is not posting. i am also trying redux, fetch and axios method but its not give me a solution
enter image description here

Custom drawer navigation isn't animating, just getting snapped to final size

I'm trying to implement this custom drawer with animation effect while sliding (opening, closing), the MainLayout should be resizing with a shrinking / growing animation when toggeling the drawer but what it does is simply changing it's size after it reache the right or left end, infact if I'm using the close button insted of pull / push through touch, upon returning it isn't growing in full sceen.
Code for Drawer:
import 'react-native-gesture-handler';
import React, {useState} from 'react';
import {StyleSheet, TouchableOpacity, Image, Text, View} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import Animated from 'react-native-reanimated';
import {
createDrawerNavigator,
DrawerContentScrollView,
useDrawerProgress,
} from '#react-navigation/drawer';
import {icons} from '../constants';
// screens import
import MainLayout from '../screens/MainLayout';
const Drawer = createDrawerNavigator();
const CustomDrawerItem = ({icon, label}) => {
return (
<TouchableOpacity // drawer item button
style={[styles.drawerItem]}
onPress={() => console.log('drawer item')}>
<Image // drawer item icon
source={icon}
style={styles.drawerItemIcon}
/>
<Text // drawer item label
style={styles.drawerItemLabel}>
{label}
</Text>
</TouchableOpacity>
);
};
const CustomDrawerContent = ({navigation}) => {
return (
<DrawerContentScrollView
scrollEnabled={true}
contentContainerStyle={{flex: 1}}>
<View style={{flex: 1, paddingHorizontal: 20}}>
<View // close button container
style={styles.closeBtnContainer}>
<TouchableOpacity // close button
style={styles.closeBtn}
onPress={() => navigation.closeDrawer()}>
<Image // close button icon
source={icons.close}
style={styles.closeBtnIcon}
resizeMode="contain"
/>
</TouchableOpacity>
</View>
<TouchableOpacity // profile button
style={styles.profileButton}
onPress={() => console.log('profile')}>
<Image // profile image
source={icons.avatar}
style={styles.profileImage}
resizeMode="cover"
/>
<View // profile text container
style={{marginLeft: 10}}>
<Text // profile name
style={styles.commonTxt}>
John Doe
</Text>
<Text // profile email
style={[styles.commonTxt, {fontSize: 15}]}>
john#xyz.com
</Text>
</View>
</TouchableOpacity>
<View // drawer items container
style={styles.drawerItmContainer}>
<CustomDrawerItem // qr code
icon={icons.qr_code}
label="QR Code"
/>
<CustomDrawerItem // resource
icon={icons.resource}
label="Resource"
/>
<CustomDrawerItem // collection report
icon={icons.collection_report}
label="Collection Report"
/>
<CustomDrawerItem // change pin
icon={icons.change_pin}
label="Change Pin"
/>
<View // separator
style={styles.separator}
/>
</View>
<View // logout button container
style={{marginBottom: 20}}>
<CustomDrawerItem // logout
icon={icons.logout}
label="Logout"
/>
</View>
</View>
</DrawerContentScrollView>
);
};
const CustomDrawer = () => {
return (
<LinearGradient
colors={['#ff9933', '#3b5998', '#192f6a']}
style={styles.container}>
<Drawer.Navigator
screenOptions={{
headerShown: false,
drawerType: 'slide',
overlayColor: 'transparent',
drawerStyle: {flex: 1, width: '65%', backgroundColor: 'transparent'},
sceneContainerStyle: {backgroundColor: 'transparent'},
}}
drawerContent={props => {
return <CustomDrawerContent navigation={props.navigation} />;
}}
initialRouteName="MainLayout">
<Drawer.Screen name="MainLayout">
{props => <MainLayout {...props} />}
</Drawer.Screen>
</Drawer.Navigator>
</LinearGradient>
);
};
export default CustomDrawer;
const styles = StyleSheet.create({
drawerItem: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 20,
alignItems: 'center',
borderRadius: 10,
},
drawerItemIcon: {width: 20, height: 20, tintColor: '#fff'},
drawerItemLabel: {fontSize: 18, color: '#fff', marginLeft: 15},
profileButton: {flexDirection: 'row', alignItems: 'center', marginTop: 20},
profileImage: {width: 50, height: 50, borderRadius: 10},
closeBtnContainer: {alignItems: 'flex-start', justifyContent: 'center'},
closeBtn: {alignItems: 'center', justifyContent: 'center'},
closeBtnIcon: {width: 30, height: 30, tintColor: '#fff'},
commonTxt: {fontSize: 18, color: '#fff'},
drawerItmContainer: {flex: 1, marginTop: 20},
separator: {height: 1, backgroundColor: '#fff', marginVertical: 10},
container: {flex: 1, backgroundColor: '#ff9f1c'},
});
Code for MainLayout:
import 'react-native-gesture-handler';
import {StyleSheet, Text, View, SafeAreaView} from 'react-native';
import React from 'react';
import Animated from 'react-native-reanimated';
import {useDrawerProgress} from '#react-navigation/drawer';
const MainLayout = props => {
const progress = useDrawerProgress();
const scale = Animated.interpolateNode(progress.value, {
inputRange: [0, 1],
outputRange: [1, 0.75],
});
const borderRadius = Animated.interpolateNode(progress.value, {
inputRange: [0, 1],
outputRange: [0, 30],
});
const animatedStyle = {
borderRadius,
transform: [{scale}],
};
return (
<Animated.View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
...animatedStyle,
}}>
<Text>MainLayout</Text>
</Animated.View>
);
};
export default MainLayout;
const styles = StyleSheet.create({});
Animation Issue:
Closing Issue:
package.json
{
"name": "Dhananjaya",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"#react-native-masked-view/masked-view": "^0.2.6",
"#react-navigation/drawer": "^6.4.1",
"#react-navigation/native": "^6.0.10",
"#react-navigation/stack": "^6.2.1",
"axios": "^0.27.2",
"native-base": "^3.4.5",
"react": "17.0.2",
"react-native": "0.68.2",
"react-native-gesture-handler": "^2.4.2",
"react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^2.8.0",
"react-native-safe-area-context": "^4.2.5",
"react-native-screens": "^3.13.1",
"react-native-svg": "^12.3.0"
},
"devDependencies": {
"#babel/core": "7.18.2",
"#babel/runtime": "7.18.3",
"#react-native-community/eslint-config": "2.0.0",
"babel-jest": "26.6.3",
"eslint": "7.32.0",
"jest": "26.6.3",
"metro-react-native-babel-preset": "0.67.0",
"react-test-renderer": "17.0.2"
},
"jest": {
"preset": "react-native"
}
}
babel.config.js
(for reference to reanimated configuration)
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'],
};
Looks like I fixed the problem, I just had to add "useLegacyImplementation" inside screenOptions prop of Drawer, Thats it.
<Drawer.Navigator
detachInactiveScreens={true}
// backBehavior="history"
screenOptions={{
headerShown: false,
drawerType: 'slide',
overlayColor: 'transparent',
drawerStyle: {flex: 1, width: '65%', backgroundColor: 'transparent'},
sceneContainerStyle: {backgroundColor: 'transparent'},
}}
drawerContent={props => {
return <CustomDrawerContent navigation={props.navigation} />;
}}
useLegacyImplementation // <-- THIS LINE
initialRouteName="Tabs">
<Drawer.Screen
name="Tabs"
component={Tabs}
options={{unmountOnBlur: true}}
/>
<Drawer.Screen
name="Profile"
component={Profile}
options={{unmountOnBlur: true}}
/>
<Drawer.Screen
name="Map"
component={Map}
options={{unmountOnBlur: true}}
/>
</Drawer.Navigator>

`useTheme` must be used within `NativeBaseConfigProvider`

In my project I faced the above error can anyone tell me how to solve this error.
The error I faced is:
Error: useTheme must be used within NativeBaseConfigProvider
This error is located at:
in Container
in ProductContainer (created by App)
in RCTView (created by View)
in View (created by App)
in App (created by ExpoRoot)
in ExpoRoot
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
ProductContainer.js:
import React, { useState, useEffect } from 'react'
import { View, StyleSheet, ActivityIndicator, FlatList, Text} from 'react-native'
import { Container, Header, Icon, Item, Input } from 'native-base';
import ProductList from './ProductList';
import SearchedProduct from './SearchedProducts';
const data = require('../../assets/data/products.json');
const ProductContainer = () => {
const [products, setProducts ] = useState([]);
const [productsFiltered, setProductsFiltered] = useState([]);
const [focus, setFocus] = useState();
useEffect(() => {
setProducts(data);
setProductsFiltered(data);
setFocus(false);
return () => {
setProducts([])
setProductsFiltered([])
setFocus()
}
}, [])
const SearchProduct = (text) => {
setProductsFiltered(
products.filter((i) => i.name.toLowerCase().includes(text.toLowerCase()))
);
}
const openList = () => {
setFocus(true);
}
const onBlur = () => {
setFocus(flase);
}
return (
<Container>
<View style = {{ flexDirection: "row"}}>
<Input
width = "100%"
variant = "rounded"
placeholder="Search"
onFocus={openList}
onChangeText={(text) => SearchProduct(text)}
/>
</View>
{focus == true ? (
<SearchProduct
productsFiltered={productsFiltered}
/>
) : (
<View style={styles.container}>
<Text>Product Container</Text>
<View style={styles.listContainer}>
<FlatList
data={products}
numColumns={2}
renderItem={({item}) => <ProductList
key={item.brand}
item={item}/>}
keyExtractor={item => item.brand}
/>
</View>
</View>
)}
</Container>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default ProductContainer
App.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
//Screens
import Header from './Shared/Header'
import ProductContainer from './Screens/Products/ProductContainer'
export default function App() {
return (
<View style={styles.container}>
<Header />
<ProductContainer />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
package.json:
{
"name": "animal-feedmart",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"expo": "~44.0.0",
"expo-status-bar": "~1.2.0",
"native-base": "^3.3.7",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-base": "^1.1.0",
"react-native-safe-area-context": "^4.2.1",
"react-native-svg": "^12.3.0",
"react-native-web": "0.17.1"
},
"devDependencies": {
"#babel/core": "^7.12.9"
},
"private": true
}
Please can anyone help me solve this issue? Thanks in advance
in your app.js import NativeBaseProvider and wrap your other components with it
import { NativeBaseProvider } from 'native-base';
return (
<NativeBaseProvider>
{Your other components}
</NativeBaseProvider>
);
If you put in the native provider and it is still showing the error, please ensure to change your Header as native base removed it from v3 upward, use HStack instead and if you want to use the Header downgrade the native base version to v2.12.14
import { NativeBaseProvider } from 'native-base';
export default function App() {
return (
<NativeBaseProvider>
<View style={styles.container}>
<Header />
<ProductContainer />
<StatusBar style="auto" />
</View>
</NativeBaseProvider>
);
}
I have solved this in App.js
import { NavigationContainer } from '#react-navigation/native';
import { NativeBaseProvider, extendTheme } from 'native-base';
Create a Theme
const newColorTheme = {
brand: {
900: '#5B8DF6',
800: '#ffffff',
700: '#cccccc',
},
};
const theme = extendTheme({
colors: newColorTheme,
});
and use on
export default function App() {
return (
<NativeBaseProvider theme={theme}>
<NavigationContainer>
<Header />
<Main/>
</NavigationContainer>
</NativeBaseProvider>
);
}

Can't find variable setUserEmail

I'm linking my backend with my frontend in react native and I get this error Can't find-variable: setUserEmail when I go to type in an email into the TextInput. I'm working on the login page and use a fetch API to log the user into the app. I followed a tutorial to the point but I'm getting this error each time I try to enter an email, I get a message say setUserEmail is declared but never used. Any help would be greately appreciated
import React, { Component, useState, createRef } from 'react';
import { StyleSheet, Text, TextInput, View, Dimensions, StatusBar, TouchableOpacity,Keyboard } from 'react-native';
export default function Login(){
const [userEmail, setUserEmail] = useState('');
const [userPassword, setUserPassword] = useState('');
const [loading, setLoading] = useState(false);
const handleSubmitPress = () => {
setLoading(true);
let dataToSend = {userEmail: userEmail, password: userPassword};
let formBody = [];
for (let key in dataToSend) {
let encodedKey = encodeURIComponent(key);
let encodedValue = encodeURIComponent(dataToSend[key]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
fetch('http://localhost:3000/users/users', {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Cache-Control": "no-cache",
Pragma: "no-cache",
Expires: "0",
},
body: JSON.stringify({
userEmail: userEmail,
password: userPassword,
os: Platform.OS === "ios" ? "iOS" : "Android",
}),
})
.then((response) => response.json())
.then((responseJson) => {
//Hide Loader
setLoading(false);
console.log(responseJson);
// If server response message same as Data Matched
if (responseJson.status === 'success') {
AsyncStorage.setItem('user_id', responseJson.data.email);
console.log(responseJson.data.email);
navigation.replace('DrawerNavigationRoutes');
} else {
setErrortext(responseJson.msg);
console.log('Please check your email id or password');
}
})
.catch((error) => {
//Hide Loader
setLoading(false);
console.error(error);
});
}
return(
<View style={style.container}>
<View style={style.parent}>
<Text style={style.title}>Login</Text>
<Text style={style.heading}>Please Sign in to continue</Text>
</View>
<View style={style.root}>
<TextInput name='txtEmail' placeholder='someone#something.com' style={style.email} onChangeText={(UserEmail) => setUserEmail(UserEmail)}/>
<TextInput type='password' name='txtPassword' placeholder='Password' secureTextEntry={true} style={style.password} onChangeText={(UserPassword) => setUserPassword(UserPassword)}/>
<Text style={style.forgotpassword}>Forgot Password?</Text>
<TouchableOpacity
title="Login"
style={style.login}
onPress={handleSubmitPress()}>
<Text style={style.login_caption}>Login </Text>
</TouchableOpacity>
</View>
<StatusBar hidden />
</View>
);
}
const style = StyleSheet.create({
container:{
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
forgotpassword:{
textAlign: 'right',
marginTop: 10,
},
login:{
width: 150,
height: 45,
backgroundColor: '#FFB900',
position: 'absolute',
right: 0,
marginLeft: 25,
marginRight: 15,
marginTop: 150,
borderRadius: 25,
},
login_caption:{
color: '#fff',
textAlign: 'left',
paddingLeft: 15,
justifyContent: 'center',
paddingTop: 12,
},
parent:{
marginTop: 85,
},
title:{
fontSize: 36,
fontWeight: "900",
paddingLeft: 25,
},
heading:{
color: '#C0C0C0',
paddingLeft: 25,
},
root:{
width: 250,
height: 350,
marginTop: 85,
alignSelf: 'center',
},
email:{
width: 275,
height:38,
borderColor: "#111",
borderWidth: 1,
fontSize: 16,
paddingLeft:10,
justifyContent: 'center',
borderRadius: 15,
alignSelf: 'center',
},
password:{
width: 275,
height:38,
borderColor: "#111",
alignSelf: 'center',
borderWidth: 1,
fontSize: 16,
paddingLeft:10,
justifyContent: 'center',
marginTop: 15,
borderRadius: 15,
}
});
UPDATED WITH CHANGES
With a little bit of cleaning, that what I ended up with:
import AsyncStorage from "#react-native-community/async-storage";
import React, { useState } from "react";
import { Dimensions, Platform, StatusBar, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
const Login = () => {
const [userEmail, setUserEmail] = useState("");
const [userPassword, setUserPassword] = useState("");
const [errorText, setErrorText] = useState("");
const [loading, setLoading] = useState(false);
const handleSubmitPress = () => {
setLoading(true);
const dataToSend = { userEmail: userEmail, password: userPassword };
let formBody = [];
for (const key in dataToSend) {
const encodedKey = encodeURIComponent(key);
const encodedValue = encodeURIComponent(dataToSend[key]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
fetch("http://localhost:3000/users/users", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Cache-Control": "no-cache",
Pragma: "no-cache",
Expires: "0",
},
body: JSON.stringify({
userEmail: userEmail,
password: userPassword,
os: Platform.OS === "ios" ? "iOS" : "Android",
}),
})
.then((response) => response.json())
.then((responseJson) => {
//Hide Loader
setLoading(false);
console.log(responseJson);
// If server response message same as Data Matched
if (responseJson.status === "success") {
AsyncStorage.setItem("user_id", responseJson.data.email);
console.log(responseJson.data.email);
// navigation.replace('DrawerNavigationRoutes');
} else {
setErrorText(responseJson.msg);
console.log("Please check your email id or password");
}
})
.catch((error) => {
//Hide Loader
setLoading(false);
console.error(error);
});
};
return (
<View style={styles.container}>
<View style={styles.parent}>
<Text style={styles.title}>Login</Text>
<Text style={styles.heading}>Please Sign in to continue</Text>
</View>
<View style={styles.root}>
<TextInput
name="txtEmail"
placeholder="someone#something.com"
style={styles.email}
onChangeText={(UserEmail) => setUserEmail(UserEmail)}
/>
<TextInput
type="password"
name="txtPassword"
placeholder="Password"
secureTextEntry={true}
style={styles.password}
onChangeText={(UserPassword) => setUserPassword(UserPassword)}
/>
<Text style={styles.forgotpassword}>Forgot Password?</Text>
<TouchableOpacity title="Login" style={styles.login} onPress={handleSubmitPress}>
<Text style={styles.login_caption}>Login </Text>
</TouchableOpacity>
</View>
<StatusBar hidden />
</View>
);
};
const styles = StyleSheet.create({
container: {
height: Dimensions.get("window").height,
width: Dimensions.get("window").width,
},
email: {
alignSelf: "center",
borderColor: "#111",
borderRadius: 15,
borderWidth: 1,
fontSize: 16,
height: 38,
justifyContent: "center",
paddingLeft: 10,
width: 275,
},
forgotpassword: {
marginTop: 10,
textAlign: "right",
},
heading: {
color: "#C0C0C0",
paddingLeft: 25,
},
login: {
backgroundColor: "#FFB900",
borderRadius: 25,
height: 45,
marginLeft: 25,
marginRight: 15,
marginTop: 150,
position: "absolute",
right: 0,
width: 150,
},
login_caption: {
color: "#fff",
justifyContent: "center",
paddingLeft: 15,
paddingTop: 12,
textAlign: "left",
},
parent: {
marginTop: 85,
},
password: {
alignSelf: "center",
borderColor: "#111",
borderRadius: 15,
borderWidth: 1,
fontSize: 16,
height: 38,
justifyContent: "center",
marginTop: 15,
paddingLeft: 10,
width: 275,
},
root: {
alignSelf: "center",
height: 350,
marginTop: 85,
width: 250,
},
title: {
fontSize: 36,
fontWeight: "900",
paddingLeft: 25,
},
});
export default Login;
There were few mistakes in your code,
you used setErrorText without declaring it.
this line <TouchableOpacity title="Login" style={styles.login} onPress={handleSubmitPress()}> was not good, maybe it was the cause of infinite rendering.
I solved all those errors very easily by using some extension in my IDE to clean code automatically like prettier and ESLint, and I used typescript. I really suggests that you do the same.

Resources