I want to create Drawer when after login. I'm not sure what I'm going to do is right.
If it's correct, how do I get back to handling setIsLogin in the App.js file?
Myapp.js
import LoginScreen from './src/screens/LoginScreen';
export default function App() {
const [isLogin, setIsLogin] = useState(false);
if(isLogin){
return(
//create Drawer here
)
}else{
return(
<LoginScreen/>
)
}
}
LoginScreen.js
const LoginScreen = ({navigation}) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const _onPress = async() => {
const payload = {
username:username,
password:password
}
};
return (
<View>
<TouchableOpacity onPress={() => _onPress()} >
<Text style={styles.textButton}>Log in</Text>
</TouchableOpacity>
</View>
)
}
export default LoginScreen;
If i misunderstand Or is there a better way, please advise me, thank you very much.
Here you go, this should work:
You can pass the setState as reference from parent to child, update the state on child and it will rerender parent.
import LoginScreen from './src/screens/LoginScreen';
export default function App() {
const [isLogin, setIsLogin] = useState(false);
if(isLogin){
return(
//create Drawer here
)
}else{
return(
<LoginScreen setLoginStatus = {setIsLogin}/>
)
}
}
const LoginScreen = ({navigation, setLoginStatus}) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const _onPress = async() =>
{
const payload = {
username:username,
password:password
}
setLoginStatus(true) //Or false depending on the payload response.
};
return (
<View>
<TouchableOpacity onPress={() => _onPress()} >
<Text style={styles.textButton}>Log in</Text>
</TouchableOpacity>
</View>
)
}
export default LoginScreen;
Related
I have a CRUD todo application where the user logs in if they are not logged in and this is stored locally. Also todo app making CRUD operations via API. But even if the user is logged in, when the page is refreshed, the login screen appears and disappears for a moment. How can I solve this?
const [todoList, setTodoList] = useState([]);
const [newTask, setNewTask] = useState("");
const [todoEditing, setTodoEditing] = useState(null);
const [editingText, setEditingText] = useState("");
const [username, setUsername] = useState("");
const [savedUsername, setSavedUsername] = useState("");
const [theme, setTheme] = useState("light");
const [addLoading, setAddLoading] = useState(false); // when adding a todo loading spinner appears in button
const [todoLoading, setTodoLoading] = useState(null); //when crud operations happen a loading spinner appears in todo cards
const [loading, setLoading] = useState(false); // loading state for crud functions
const [loginLoading, setLoginLoading] = useState(false); // loading screen for app rendering
useEffect(() => {
setLoginLoading(true);
const storageUsername = localStorage.getItem("username");
if (storageUsername) {
setSavedUsername(storageUsername);
}
setLoginLoading(false);
}, []);
<ThemeContext.Provider value={{ theme }} style={{ position: "relative" }}>
{savedUsername ? (
<div className="container">
.... Components
</div> ) : (
<div className="login-container" id={theme}>
{loginLoading ? (
<Loading />
) : (
<Login
handleChange={setUsername}
handleLogin={handleLogin}
value={username}
/>
)}
</div>
)}
</ThemeContext.Provider>
Your effect from useEffect is only executed after your first render. So your first state for the loginLoading is false then true and then false again. This should fix it:
const [todoList, setTodoList] = useState([]);
const [newTask, setNewTask] = useState("");
const [todoEditing, setTodoEditing] = useState(null);
const [editingText, setEditingText] = useState("");
const [username, setUsername] = useState("");
const [savedUsername, setSavedUsername] = useState("");
const [theme, setTheme] = useState("light");
const [addLoading, setAddLoading] = useState(false); // when adding a todo loading spinner appears in button
const [todoLoading, setTodoLoading] = useState(null); //when crud operations happen a loading spinner appears in todo cards
const [loading, setLoading] = useState(false); // loading state for crud functions
const [loginLoading, setLoginLoading] = useState(true); // loading screen for app rendering
useEffect(() => {
const storageUsername = localStorage.getItem("username");
if (storageUsername) {
setSavedUsername(storageUsername);
}
setLoginLoading(false);
}, []);
<ThemeContext.Provider value={{ theme }} style={{ position: "relative" }}>
{savedUsername ? (
<div className="container">
.... Components
</div> ) : (
<div className="login-container" id={theme}>
{loginLoading ? (
<Loading />
) : (
<Login
handleChange={setUsername}
handleLogin={handleLogin}
value={username}
/>
)}
</div>
)}
</ThemeContext.Provider>
But, to improve even more, I wouldn't use a loading state for the login because localStorage.getItem("username") is a synchronous operation that can be performed more elegantly like that:
const [todoList, setTodoList] = useState([]);
const [newTask, setNewTask] = useState("");
const [todoEditing, setTodoEditing] = useState(null);
const [editingText, setEditingText] = useState("");
const [username, setUsername] = useState("");
const [savedUsername, setSavedUsername] = useState(() => localStorage.getItem("username") || "");
const [theme, setTheme] = useState("light");
const [addLoading, setAddLoading] = useState(false); // when adding a todo loading spinner appears in button
const [todoLoading, setTodoLoading] = useState(null); //when crud operations happen a loading spinner appears in todo cards
const [loading, setLoading] = useState(false); // loading state for crud functions
<ThemeContext.Provider value={{ theme }} style={{ position: "relative" }}>
{savedUsername ? (
<div className="container">
.... Components
</div> ) : (
<div className="login-container" id={theme}>
<Login
handleChange={setUsername}
handleLogin={handleLogin}
value={username}
/>
</div>
)}
</ThemeContext.Provider>
I am using React Native Flatlist for pagination but unable to re-render after apply sorting or filter.
Simple appending working //setResult(response.data.response.products.data);
With Concinate not working // setResult([...result, ...response.data.response.products.data]);
Note: Also used extraData prop but not working...
import React, {useState, useEffect, useContext} from 'react';
import {
SafeAreaView,
View,
Text,
StyleSheet,
FlatList,
ActivityIndicator,
} from 'react-native';
export default function GrSubCategoryLevel2(props) {
const {navigation} = props;
const [loading, setLoading] = useState(true);
const [hasError, setHasError] = useState(false);
const [result, setResult] = useState([]);
const [data, setData] = useState([]);
const [page, setPage] = useState(1);
const [loadMore, setLoadMore] = useState(true);
const [popularValue, setPopularValue] = useState(null);
const [priceValue, setPriceValue] = useState('');
useEffect(() => {
fetchData(page);
}
}, []);
const fetchData = async (page) => {
if (loadMore) {
const request = subCategoriesLevel2(page);
try {
const response = await axios({
url: request.url,
method: request.method,
data: request.data,
headers: {
'Content-Type': 'application/json',
'Accept-Language': 'en',
Accept: 'application/json',
},
});
if (!response.data.error) {
setData(response.data.response);
if (response.data.response.products.data.length > 0) {
setResult([...result, ...response.data.response.products.data]);
//setResult(response.data.response.products.data);
if (response.data.response.products.next_page_url !== null) {
setPage(page + 1);
setLoadMore(true);
} else {
setLoadMore(false);
}
}
setLoading(false);
}
} catch (error) {
if (error) {
console.log('Error', error.message);
}
}
}
};
const renderItem = ({item}) => (
<SubCategoryProduct
data={item}
navigation={navigation}
/>
);
return (
<SafeAreaView style={styles.container}>
<Navbar navigation={navigation} />
<View style={styles.container}>
<View style={styles.container}>
<View style={styles.subCategoryList}>
<FlatList
data={result}
extraData={result}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
columnWrapperStyle={{justifyContent: 'space-between'}}
numColumns={3}
keyExtractor={(item, index) => item.id}
onEndReached={() =>
fetchData()
}
stickyHeaderIndices={[0]}
ListFooterComponent={
<View style={styles.loaderFooter}>
{loadMore && (
<ActivityIndicator
color={Colors.secondary}
size="small"
/>
)}
</View>
}
/>
</View>
</View>
</View>
</SafeAreaView>
);
}
I think what you're doing is not the right way of concatenating in using useState() hooks. You need to know that in order to update/concatenate, the right way is to:
Make a copy of the previous item, and add it to the list with an updated data.
// Here previousData is a copy of the previous list which is maintained in the state data
setResult(previousData => [...previousData, response.data.response.products.data]);
OR
setResult(previousData => {
return [...previousData, response.data.response.products.data]
});
Appreciation: I like your work by the way Ajay. Pretty neat and professional, keep up the good work 👏🏻👏🏻
I have an input which passes its value to a useState on its parent.
That value gets passed to other component (Custom button).
There the input data gets validated and returns to the parent in another useState if there's an error and where ("e" = error in email, "p" = error in password, "ep" = error in email and password)
Then the border color of the input is set accordingly to that response, if there is an error it turns red, otherwise it turns white.
But it only works the second time i press the button (With which everything is supposed to start)
HELP!😣
const LoginScreen = () => {
const [email, setemail] = useState('');
const [password, setpassword] = useState('');
const [error, seterror] = useState('');
return (
<View style={styles.container}>
<Input
placeholder={"Correo :"}
setInputValue={value => setemail(value)}
color={
error.includes("e") ? '#FA8072' : 'white'
}
/>
<Input
placeholder={"Contraseña :"}
setInputValue={value => setpassword(value)}
color={
error.includes("p") ? '#FA8072' : 'white'
}
/>
<LoginButton data={{email: email, password: password}} setValue={value => {seterror(value)}}/>
</View>
)
}
=========================================
Input component
const Input = (props) => {
return (
<View style={styles.container}>
<Text style={styles.placeholder}>{props.placeholder}</Text>
<TextInput
style={[styles.input, {borderColor: props.color}]}
onChangeText={(value) => props.setInputValue(value)}
/>
</View>
)
}
=========================================
Button component
const LoginButton = (props) => {
const [inputError, setinputError] = useState('')
let validateData = () => {
if(!props.data.email && !props.data.password){
setinputError('ep')
}
else if(!props.data.email){
setinputError('e')
}
else if(!props.data.password){
setinputError('p')
}
else {
setinputError('')
}
}
return (
<TouchableOpacity style={styles.mainButton} onPress={() => {validateData(); props.setValue(inputError)}}>
<Text style={styles.mainButtonText}>Iniciar sesión</Text>
</TouchableOpacity>
)
}
Because you're trying to change state twice. Actually you don't need use state to pass value at LoginButton component. Try direct call instead.
const LoginButton = (props) => {
let validateData = () => {
if(!props.data.email && !props.data.password){
props.setValue("ep");
}
else if(!props.data.email){
props.setValue('e');
}
else if(!props.data.password){
props.setValue('p');
}
else {
props.setValue('');
}
}
return (
<TouchableOpacity style={styles.mainButton} onPress={() => validateData()}>
<Text style={styles.mainButtonText}>Iniciar sesión</Text>
</TouchableOpacity>
)
}
I am trying to do a basic todo list however when I dispatch an action after pressing add it doesn't dispatch .
I've taken the dispatch(todo(todoList))out of every function and left it in the main ToDo component to do multiple calls on every letter typed into the search box and I can see an update in my redux store in Redux-dev tools so I know my todo works but It won't dispatch() when I try to submit. Please can someone help me .
This is my code:
import {useDispatch } from 'react-redux'
import { todo } from './action/todo'
const ToDo = () => {
const [todo, setTodo] = useState('')
const [todoList, setTodoList] = useState([])
const dispatch = useDispatch()
const handleSubmit = (id , todo) => {
const newTodoList = todoList.concat({ id: id, val: todo })
return (
setTodo(''),
todo.length === 0
? <Text/>
: setTodoList(newTodoList) // if I put the dispatch here it doesn't work either
)
}
return (
<View style={styles.addPhotoCont}>
<TextInput
placeholder={props.textInputPlaceholder}
onChangeText={props => setTodo(props)}
value={todo}
/>
<TouchableOpacity
onPress={() => handleSubmit(Date.now(), todo) && dispatch(todo(todoList))}>
<Text style={styles.addButton}>Add</Text>
</TouchableOpacity>
</View>
)
}
It looks like you set todo twice, once as an import, and the second time as state. When you call dispatch and pass in todo it is calling the state version.
You should put the dispatch in the handleSubmit function.
Also, looking at the handleSubmit function, the return will not work. You can only return one thing. You can place the other functions above the return statement.
Edit:
Code sample below:
import { useDispatch } from 'react-redux'
import { todo } from './action/todo'
const ToDo = (props) => {
const [todoInputValue, setTodoInputValue] = useState('')
const dispatch = useDispatch()
const handleSubmit = (todo) => {
dispatch(todo({id: Date.now(), val: todoInputValue}))
setTodoInputValue('')
}
return (
<View style={styles.addPhotoCont}>
<TextInput
placeholder={props.textInputPlaceholder}
onChangeText={value => setTodoInputValue(value)}
value={todoInputValue}
/>
<TouchableOpacity
onPress={() => handleSubmit(Date.now())}>
<Text style={styles.addButton}>Add</Text>
</TouchableOpacity>
</View>
)
}
I am trying to pass values from one Functional Component to another Functional Component on navigation.navigate, on the first screen the value is there I can see it rendering it or on console.log, but when I try to get it on the second screen I get it "undefined".
Here I pass the value to the navigation.navigate:
<TouchableOpacity onPress = {() => navigation.navigate('AuditS',{audit:r.id})} style={styles.button}>
I will post my code bellow, if someone can give me a help I'll really appreciate it.
First Component:
import React, { createElement, useState, useEffect } from 'react';
import { Text, StyleSheet, View,TouchableOpacity,Image} from 'react-native';
import AuditButton from './component/AuditButton'
import axios from 'axios'
const HomeScreen = ({ navigation }) => {
const [checklists, setChecklists] = useState([]);
useEffect(() => {
axios.get("http://100.13.16.113:8081/api/checklists", {
}).then
(function (response) {
setChecklists(response.data);
console.log(response.data);
}).catch(error => {
console.log(error);
})
},[]);
return (
<View >
<Text style={styles.text}> Select an Audit</Text>
<View style={styles.maincontainer}>
<View style={styles.container}>
{checklists.map(r =>(
<TouchableOpacity onPress = {() => navigation.navigate('AuditS',{audit:r.id})} style={styles.button}>
<Image source={require('../assets/icons8-audit-80.png')}
style={styles.Image}>
</Image>
<Text style={styles.ButtonText}>{r.checklisT_DESCRIPTION}{r.id}</Text>
</TouchableOpacity >
))}
</View>
</View>
<View style={styles.bottomcontainer}>
<TouchableOpacity onPress = {() => navigation.navigate('Login')}
>
<Text style = {styles.logout}>LOGOUT</Text>
</TouchableOpacity>
</View>
</View>
);
};
Second Component:
import React, { createElement, useState,Component } from 'react';
import { Text, TextInput, StyleSheet,
View,TouchableOpacity,Image,ScrollView,Modal,TouchableHighlight} from 'react-native';
import {Collapse,CollapseHeader, CollapseBody} from 'accordion-collapse-react-native';
import AuditItem from './component/AuditItem'
import RNPickerSelect from 'react-native-picker-select';
import AuditCategory from './component/AuditCategory';
const AuditScreen = ({ audit, navigation}) =>
{
const [modalInfoVisible, setModalInfoVisible] = useState(false);
const [opNumber, setOP] = useState(false);
const [FGINumber, setFGI] = useState(false);
const [checklistitems, setChecklistitems] = useState([]);
const auditId = audit;
console.log(JSON.stringify(auditId));
return ()
I'd suggest you to use react-router-dom if you are working with router.
make some changes in second component like
const AuditScreen = () => //some changes in line
{
const {audit} = navigation.state.params; //added line
const [modalInfoVisible, setModalInfoVisible] = useState(false);
const [opNumber, setOP] = useState(false);
const [FGINumber, setFGI] = useState(false);
const [checklistitems, setChecklistitems] = useState([]);
const auditId = audit;
console.log(JSON.stringify(auditId));
return ()
Hope it helps!!!