My first idea was to try to delete items from a nested list. I've started using SectionList and a component that has an useState that manages the data changes of the SectionList. I'm trying to solve it using SectionList but it'd be great to display all possible alternatives (FlatList, ViewList, etc).
I figured out how to delete a whole section list (and his items) but not one item by one. I've read plenty of posts, but I did find nothing related to managing SectionList items. Maybe there's an answer out there for FlatList nested items.
Here I left an example code ready to use (without styles) based on React Native official docs:
import React, { useEffect } from "react";
import { StyleSheet, Text, View, SafeAreaView, SectionList, StatusBar, Button } from "react-native";
import { useState } from "react";
const dataResource = [
{
title: "Main dishes",
data: ["Pizza", "Burger", "Risotto"],
n: "delete",
k: 1
},
{
title: "Sides",
data: ["French Fries", "Onion Rings", "Fried Shrimps"],
n: "delete",
k: 2
},
];
function App() {
const [state, setState] = useState(dataResource)
const Item = ({ dish, obj, i}) => (
<View >
<Text >{dish} </Text>
<Button title={obj.n} onPress={() => {}} /> // add the handler
</View>
);
const SectionComponent = ({ t, k }) => (
<View>
<Text >{t} </Text>
<Button title={'section'} onPress={() => { setState(state.filter(e => e.k != k)) }} />
</View>
);
return (
<SafeAreaView >
<SectionList
sections={state}
keyExtractor={(item, index) => item + index}
renderItem={({ item, section, index}) => <Item dish={item} obj={section} i={index}/>}
renderSectionHeader={({ section: { title, k } }) => <SectionComponent k={k} t={title} />}
/>
</SafeAreaView>
);
}
export default App;
I think how you display the data is trivial. The component you use will just change how you access the data, not how you update it. What you need is helper functions for editing the data. With those in place you can do things like add/remove section items, and editing section items themselves:
import React, { useState } from 'react';
import {
Text,
View,
StyleSheet,
SafeAreaView,
SectionList,
Button,
TextInput,
} from 'react-native';
const dataResource = [
{
title: 'Main dishes',
data: ['Pizza', 'Burger', 'Risotto'],
id: 1,
},
{
title: 'Sides',
data: ['French Fries', 'Onion Rings', 'Fried Shrimps'],
id: 2,
},
];
export default function App() {
const [state, setState] = useState(dataResource);
const [sectionTitle,setSectionTitle] = useState('Drinks')
const editItem = (itemId, newValue) => {
let newState = [...state];
let itemIndex = newState.findIndex((item) => item.id == itemId);
if (itemIndex < 0) return;
newState[itemIndex] = {
...newState[itemIndex],
...newValue,
};
setState(newState);
};
const addSectionItem = (title)=>{
let newState = [...state]
newState.push({
title,
data:[],
id:newState.length+1
})
setState(newState)
}
const removeFood = (itemId, food) => {
let currentItem = state.find((item) => item.id == itemId);
console.log(currentItem);
currentItem.data = currentItem.data.filter((item) => item != food);
console.log(currentItem.data);
editItem(itemId, currentItem);
};
const addFood = (itemId, food) => {
let currentItem = state.find((item) => item.id == itemId);
console.log(currentItem.data);
currentItem.data.push(food);
console.log(currentItem.data);
editItem(itemId, currentItem);
};
const Item = ({ item, section, index }) => {
return (
<View style={styles.row}>
<Text>{item} </Text>
<Button
title={'Delete'}
onPress={() => {
removeFood(section.id, item);
}}
/>
</View>
);
};
const SectionHeader = ({ title, id }) => {
return (
<View style={styles.header}>
<Text style={{ fontSize: 18 }}>{title} </Text>
<Button
title={'X'}
onPress={() => {
setState(state.filter((e) => e.id != id));
}}
/>
</View>
);
};
const SectionFooter = ({ id }) => {
const [text, setText] = useState('');
return (
<View style={[styles.row, styles.inputWrapper]}>
<Text>Add Entry</Text>
<TextInput
value={text}
onChangeText={setText}
style={{ borderBottomWidth: 1 }}
/>
<Button title="Add" onPress={() => addFood(id, text)} />
</View>
);
};
return (
<SafeAreaView>
<Button title="Reset list" onPress={() => setState(dataResource)} />
<View style={[styles.row, styles.inputWrapper]}>
<Text>Add New Section</Text>
<TextInput
value={sectionTitle}
onChangeText={setSectionTitle}
style={{ borderBottomWidth: 1 }}
/>
<Button title="Add" onPress={() => addSectionItem(sectionTitle)} />
</View>
<View style={styles.sectionListWrapper}>
<SectionList
sections={state}
keyExtractor={(item, index) => item + index}
renderItem={Item}
renderSectionHeader={({ section }) => <SectionHeader {...section} />}
renderSectionFooter={({ section }) => <SectionFooter {...section} />}
/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
width: '100%',
justifyContent: 'space-between',
padding: 5,
alignItems: 'center',
},
header: {
flexDirection: 'row',
paddingVertical: 5,
width: '100%',
borderBottomWidth: 1,
},
inputWrapper: {
paddingVertical: 15,
marginBottom: 10,
},
sectionListWrapper: {
padding: 5,
},
});
Here's a demo
I've improved my answer to give a clearer example of how to manipulate SectionList. An example of how to add/delete/modify sections and its data is provided.
import React from 'react';
export default function useStateHelpers(state, setState) {
const editSection = (sectionId, newValue) => {
// parse and stringify is used to clone properly
let newState = JSON.parse(JSON.stringify(state));
let itemIndex = newState.findIndex((item) => item.id == sectionId);
if (itemIndex < 0) return;
const section = {
...newState[itemIndex],
...newValue,
};
newState[itemIndex] = section;
setState(newState);
};
const editSectionDataItem = (sectionId, itemId, newValue) => {
const newState = JSON.parse(JSON.stringify(state));
const sectionIndex = newState.findIndex(
(section) => section.id == sectionId
);
const section = newState[sectionIndex];
const itemIndex = section.data.findIndex((item) => item.id == itemId);
let item = section.data[itemIndex];
section.data[itemIndex] = {
...item,
...newValue,
};
editSection(sectionId, section);
};
const editSectionTitle = (sectionId, title) =>
editSection(sectionId, { title });
const setSelectSectionItem = (sectionId, itemId, isSelected) => {
editSectionDataItem(sectionId, itemId, { isSelected });
};
const removeSectionDataItem = (sectionId, food) => {
let newState = JSON.parse(JSON.stringify(state));
let sectionIndex = newState.findIndex((section) => section.id == sectionId);
let section = newState[sectionIndex];
section.data = section.data.filter((item) => item.title != food);
editSection(sectionId, section);
};
const addSectionDataItem = (sectionId, title, price) => {
let newState = JSON.parse(JSON.stringify(state));
let sectionIndex = newState.findIndex((section) => section.id == sectionId);
let section = newState[sectionIndex];
section.data.push({
title,
price,
id: `section-${sectionId}-${section.data.length + 1}`,
});
editSection(sectionId, section);
};
const addSection = (title, data = [], id) => {
let newState = JSON.parse(JSON.stringify(state));
newState.push({
title,
data,
id: newState.length + 1,
});
setState(newState);
};
const helpers = {
editSection,
editSectionTitle,
removeSectionDataItem,
addSectionDataItem,
addSection,
setSelectSectionItem,
editSectionDataItem,
};
return helpers;
}
import React, { useState } from 'react';
import {
StyleSheet,
SafeAreaView,
View,
Button,
SectionList,
} from 'react-native';
import data from './data';
import StateContext from './StateContext';
import useStateHelpers from './hooks/useStateHelpers';
import Header from './components/SectionHeader';
import Footer from './components/SectionFooter';
import Item from './components/SectionItem';
import TextInput from './components/Input';
export default function App() {
const [state, setState] = useState(data);
const [sectionTitle, setSectionTitle] = useState('');
const helpers = useStateHelpers(state, setState);
return (
<SafeAreaView style={{ flex: 1 }}>
<StateContext.Provider value={{ state, setState, ...helpers }}>
<View style={styles.container}>
<Button title="Reset list" onPress={()=>setState(data)} />
<TextInput
label={'Add New Section'}
value={sectionTitle}
onChangeText={setSectionTitle}
onRightIconPress={() => {
helpers.addSection(sectionTitle);
setSectionTitle('');
}}
/>
<View style={styles.sectionListWrapper}>
<SectionList
style={{ flex: 1 }}
sections={state}
renderItem={(props) => <Item {...props} />}
renderSectionHeader={(props) => <Header {...props} />}
renderSectionFooter={(props) => <Footer {...props} />}
/>
</View>
</View>
</StateContext.Provider>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 8,
},
sectionListWrapper: {
padding: 5,
flex: 1,
},
});
import React, { useContext } from 'react';
import { View, TouchableOpacity, StyleSheet, Text, Button } from 'react-native';
import StateContext from '../StateContext';
export default function Item({ item, section, index }) {
const {
removeSectionDataItem,
setSelectSectionItem
} = useContext(StateContext);
const hasPrice = item.price.toString().trim().length > 0;
return (
<TouchableOpacity
style={[styles.container, item.isSelected && styles.selectedContainer]}
onPress={() =>
setSelectSectionItem(section.id, item.id, !item.isSelected)
}
>
<View style={styles.row}>
<Text>
{item.title + (hasPrice ? ' | ' : '')}
{hasPrice && <Text style={{ fontWeight: '300' }}>{item.price}</Text>}
</Text>
<Button
title={'Delete'}
onPress={() => {
removeSectionDataItem(section.id, item.title);
}}
/>
</View>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
container: {
marginVertical: 2,
},
selectedContainer: {
backgroundColor: 'rgba(0,0,0,0.2)',
},
row: {
flexDirection: 'row',
width: '100%',
justifyContent: 'space-between',
padding: 5,
alignItems: 'center',
},
});
/*SectionFooter.js*/
import React, { useState, useContext, useEffect } from 'react';
import { View, StyleSheet, Text } from 'react-native';
import TextInput from './Input';
import StateContext from '../StateContext';
export default function SectionFooter({ section }) {
const [title, setTitle] = useState('');
const [price, setPrice] = useState('');
const [titleWasEdited, setTitleWasEdited] = useState(false);
const { addSectionDataItem, editSectionDataItem } = useContext(StateContext);
const selectedItem = section.data.find((item) => item.isSelected);
// listen for item selection
useEffect(() => {
// pass item values to text input
setTitle(selectedItem?.title || '');
setPrice(selectedItem?.price || '');
// reset title/price input
setTitleWasEdited(false);
}, [selectedItem]);
return (
<View style={styles.container}>
<Text>
{selectedItem
? 'Editing ' + selectedItem.title
: 'Add New Entry'
}
</Text>
{/*one input handles both title and price*/}
<TextInput
label={titleWasEdited ? 'Price' : 'Title'}
value={titleWasEdited ? price : title}
onChangeText={titleWasEdited ? setPrice : setTitle}
rightIconName={titleWasEdited ? 'plus' : 'arrow-right'}
// rightIcon is disabled when theres no text
// but price is allowed to be empty
allowEmptySubmissions={titleWasEdited}
style={{ width: '80%' }}
onRightIconPress={() => {
// after title is edited allow submission
if (titleWasEdited) {
// if item was edited update it
if (selectedItem) {
editSectionDataItem(section.id, selectedItem.id, {
title,
price,
isSelected: false,
});
}
// or add new item
else {
addSectionDataItem(section.id, title, price);
}
setTitle('');
setPrice('');
}
// toggle between title & price
setTitleWasEdited((prev) => !prev);
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
marginVertical: 20,
alignItems: 'center',
},
});
import React, { useContext } from 'react';
import { View, StyleSheet } from 'react-native';
import { TextInput } from 'react-native-paper';
import StateContext from '../StateContext';
export default function SectionHeader({ section: { id, title } }) {
const { editTitle, setState, state } = useContext(StateContext);
return (
<View style={{ borderBottomWidth: 1 }}>
<View style={styles.header}>
<TextInput
style={styles.titleInput}
value={title}
onChangeText={(text) => {
editTitle(id, text);
}}
right={
<TextInput.Icon
name="close"
onPress={() => {
setState(state.filter((sec) => sec.id != id));
}}
/>
}
underlineColor="transparent"
activeUnderlineColor="transparent"
outlineColor="transparent"
activeOutlineColor="transparent"
selectionColor="transparent"
dense
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
header: {
flexDirection: 'row',
width: '100%',
justifyContent: 'space-around',
alignItems: 'center',
},
titleInput: {
fontSize: 18,
backgroundColor: 'transparent',
borderWidth: 0,
borderColor: 'transparent',
height: 36,
},
});
I want to use onScrollBegin on my flatlist. But everytime I make scroll the function runs. I only want to run this function when I am at the top, not everytime I scroll.
import * as React from 'react';
import { StyleSheet, Text, View, Pressable, Image, Dimensions, Platform, FlatList, TextInput } from 'react-native';
import { messages } from '../utils/mockChat';
import { useDispatch, useSelector } from 'react-redux';
import moment from 'moment';
import Modal from 'react-native-modalbox';
import { openModalImage } from '../redux/slice/chat/chatSlice';
const { width, height } = Dimensions.get('screen');
function propsEqual(prevProp, nextProp) {
if(prevProp.id === nextProp.id) {
return true;
}
}
const Item = React.memo(({ global_user_id, id, type, render, allDates, name, user_id, reciever, text, images, video, sending, pending, read, date }) => {
const dateNum = moment(date).format('DD-MM-YYYY');
return (
<View style={s.item}>
<View style={s.itemContainer}>
<View style={global_user_id === user_id ? s.ownerText : s.reciever_text}>
<Text style={s.text}>{ text }</Text>
</View>
</View>
</View>
)
}, propsEqual);
const userState = state => state.user.userID;
const modalState = state => state.chatSlice.modalImage;
const Chat = ({ route, navigation }) => {
const { image } = route.params;
const dispatch = useDispatch();
const modalSec = useSelector(modalState);
const userID = useSelector(userState);
const [message, setMessage] = React.useState(generateItems(messages));
const modalR = React.useRef(null);
const timerCloseModal = React.useRef(null);
React.useEffect(() => {
modalSec && modalR.current.open();
}, [modalSec]);
const dates = new Set();
function renderDate(date) {
dates.add(moment(date).format('DD-MM-YYYY'));
return (
<Text style={{color: '#333', fontSize: 12}}>{moment(date).format('DD-MM-YYYY')}</Text>
)
}
const showFooter = () => {
return (
<View style={s.footerContainer}>
<TextInput style={{height: 50, width: '100%', padding: 20}} />
</View>
)
};
const rowRenderer = ({ item }) => {
return (
<Item
item={item}
id={item.id}
allDates={dates}
render={(date) => renderDate(date)}
global_user_id={userID}
name={item.name}
user_id={item.user_id}
reciever={item.reciever}
text={item.text}
images={item.images}
video={item.video}
sending={item.sending}
pending={item.pending}
read={item.read}
type={item.type}
date={item.date} />
)
};
const closeModalImage = React.useCallback(() => {
dispatch(openModalImage());
}, [dispatch, modalR]);
return (
<View style={s.container}>
<FlatList
data={message}
keyExtractor={i => i.id.toString()}
renderItem={rowRenderer}
initialNumToRender={10}
onScrollBeginDrag={() => {
console.log('s');
// setMessage(items);
}}
extraData={message}
ListHeaderComponent={showFooter}
inverted
/>
</View>
)
};
const s = StyleSheet.create({
container: {
flex: 1
},
modal: {
justifyContent: 'center',
alignItems: 'center',
width: 300,
height: 300,
borderRadius: 200,
backgroundColor: 'transparent',
maxHeight: 500,
},
item: {
backgroundColor: 'red',
height: 250,
width: width * 0.8,
marginVertical: 12
},
ownerText: {
alignSelf: 'flex-end',
backgroundColor: 'blue'
},
reciever_text: {
alignSelf: 'flex-start'
}
});
export default Chat;
How can I fix it, that I can only scroll if I am on the top? I use inverted so its hard for me, to know where is the top position. I am very thankful for your help
Make use of the onEndReached prop.
The onEndReached function calls every time you reach the end of a list.
official doc
I'm new to react native, this is an application that scans Qr codes I want to have two buttons one that scans again and one that redirects to a new screen called 'List' with the QR code data. However after scanning the QR code and every time i press the scan again or result button the expo application crashes this is my code:
import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { Link } from "react-router-dom"
import CryptoJS from 'crypto-js';
import { decode } from 'base-64';
import { useNavigation } from '#react-navigation/native';
export default function Scan({ navigation }) {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [text, setText] = useState('Not yet scanned')
const askForCameraPermission = () => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})()
}
// Request Camera Permission
useEffect(() => {
askForCameraPermission();
}, []);
// What happens when we scan the bar code
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
var master_key = '5486231058798416'
// Decode the base64 data so we can separate iv and crypt text.
var rawData = decode(data);
// Split by 16 because my IV size
var iv = rawData.substring(0, 16);
var crypttext = rawData.substring(16);
//Parsers"
crypttext = CryptoJS.enc.Latin1.parse(crypttext);
iv = CryptoJS.enc.Latin1.parse(iv);
var key = CryptoJS.enc.Utf8.parse(master_key);
// Decrypt
var plaintextArray = CryptoJS.AES.decrypt(
{ ciphertext: crypttext},
key,
{iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7}
);
// Can be Utf8 too
var output_plaintext = CryptoJS.enc.Latin1.stringify(plaintextArray).json();
console.log("plain text : " + output_plaintext);
setText(output_plaintext.json())
console.log('Type: ' + type + '\nData: ' + data)
};
// Check permissions and return the screens
if (hasPermission === null) {
return (
<View style={styles.container}>
<Text>Requesting for camera permission</Text>
</View>)
}
if (hasPermission === false) {
return (
<View style={styles.container}>
<Text style={{ margin: 10 }}>No access to camera</Text>
<Button title={'Allow Camera'} onPress={() => askForCameraPermission()} />
</View>)
}
// Navigation
function MyBackButton() {
const navigation = useNavigation();
return (
<Button
title="Result"
onPress={() => {
navigation.navigate('List');
}}
/>
);
}
// Return the View
return (
<View style={styles.container}>
<View style={styles.barcodebox}>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={{ height: 400, width: 400 }} />
</View>
{scanned && <Button title={'Result'} onPress={() => MyBackButton()} color='black' />}
{scanned && <Button title={'Scan again?'} onPress={() => setScanned(false)} color='black' />}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
maintext: {
fontSize: 16,
margin: 20,
},
barcodebox: {
alignItems: 'center',
justifyContent: 'center',
height: 300,
width: 300,
overflow: 'hidden',
borderRadius: 30,
backgroundColor: 'black'
}
});
in your code MyBackButton not just a function, it return a view -> crash.
Fix your func MyBackButton =>
// Navigation
function MyBackButton() {
const navigation = useNavigation();
navigation.navigate('List');
}
Rename your MyBackButton -> myBackAction
I am trying to search items in a flatlist, whenever i type in the search bar it only take one letter and closes the keyboard and the value inside the search bar disappear,
example when i type "george" it only takes the letter g and re-render a list of names containing the letter g and delete what's inside the search bar
how can i fix this ?
import React, { useState, useEffect } from 'react';
import { ScrollView } from 'react-native';
import { View, Text, FlatList, ActivityIndicator, SafeAreaView, TouchableOpacity } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { Divider, SearchBar } from 'react-native-elements'
const Item = ({ name, lastName }) => (
<View>
<Text style={{ fontSize: 17, color: '#666', marginBottom: 10 }}>Full name: {name} {lastName}</Text>
</View>);
function Clients({ navigation }) {
const [isLoading, setLoading] = useState(true);
const usersApi = 'https://reqres.in/api/users'
const [users, setUsers] = useState([]);
const [search, setSearch] = useState("");
const [masterData, setMasterData] = useState("");
const fetchJson = async (userApi) => {
const response = await fetch(userApi);
return response.json()
}
useEffect(() => {
fetchJson(usersApi)
.then((users) => {
setUsers(users.data);
setMasterData(users.data);
})
.catch((error) => (alert(error)))
.finally(() => setLoading(false));
}, []);
const itemSeparator = () => {
return (
<Divider style={{ width: "105%", marginVertical: 3, alignSelf: 'center' }} />
)
}
const renderHeader = () => {
return (
<SearchBar
placeholder="Type Here..."
lightTheme
round
onChangeText={text => searchFilterFunction(text)}
autoCorrect={false}
/>
);
};
const searchFilterFunction = text => {
setSearch(text);
const newData = masterData.filter(item => {
const itemData = `${item.first_name.toUpperCase()} ${item.last_name.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setUsers(newData);
};
const renderItem = ({ item }) => (
<TouchableOpacity style={{
flex: 1,
padding: 10
}}
onPress={() => { navigation.navigate('Client', { item: item }); }}
underlayColor='#ccc'
activeOpacity={0.1} >
<Item name={item.first_name} lastName={item.last_name} />
</TouchableOpacity>
);
console.log(search)
console.log(users)
return (
<SafeAreaProvider>
<SafeAreaView>
<Text style={{ color: '#666', margin: 15, fontSize: 20 }}>Clients actuels</Text>
<View style={{
width: '96%',
backgroundColor: 'white',
borderRadius: 5,
alignSelf: 'center',
marginTop: 20,
}}>
<View style={{ margin: 15 }}>
{isLoading ? <ActivityIndicator size="large" /> :
<FlatList
data={users}
renderItem={renderItem}
ItemSeparatorComponent={itemSeparator}
ListHeaderComponent={renderHeader}
keyExtractor={item => item.id.toString()}
value={search}
/>}
</View>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}
export default Clients;
I've created a login page where it has 2 input fields (username, password). To generate those input fields i am using "Input" component from nativebase. Now i want to focus password field from username input field when user press next from keyboard. But i am having a hard time finding this solution, can anyone help me out with that? Here is my code:
//packages
import React, { createRef, useContext, useEffect, useState } from 'react';
import { Image, Keyboard, ScrollView, StyleSheet, Text, View } from 'react-native';
import { AuthContext } from './context';
// third pirty packages
import { Button, Item, Input, Root, Spinner } from 'native-base';
import FontAwesome from "react-native-vector-icons/FontAwesome";
import Feather from "react-native-vector-icons/Feather";
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
listenOrientationChange as lor,
removeOrientationListener as rol
} from 'react-native-responsive-screen';
//assets and components
import logoImageSmall from './../android/app/src/main/res/drawable/logo_small.png';
export const LoginScreen = ({ route, navigation }) => {
const [site_url, setSiteUrl] = useState(route.params.site_url);
const [database_name, setDatabaseName] = useState(route.params.database_name);
const [institute_name, setInstituteName] = useState(route.params.institute_name);
const [logo_location, setLogoLocation] = useState(route.params.logo_location);
const [student_id, setStudentId] = useState('');
const [password, setPassword] = useState('');
const [showLogo, setShowLogo] = useState(true);
const { state, signInAction } = useContext(AuthContext);
let passwordRef = React.createRef();
useEffect(() => {
lor();
const keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
() => {
_keyboardDidShow();
}
);
const keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
() => {
_keyboardDidHide();
}
);
return () => {
rol();
keyboardDidHideListener.remove();
keyboardDidShowListener.remove();
};
}, []);
let _keyboardDidHide = () => {
setShowLogo(true);
}
let _keyboardDidShow = () => {
setShowLogo(false);
}
const styles = StyleSheet.create({
............
// my styles
............
});
return (
<Root>
<ScrollView contentContainerStyle={styles.loginForm} keyboardShouldPersistTaps="handled">
<Item rounded style={{ borderColor: "#FF3C48" }}>
<FontAwesome name='user' style={styles.iconStyle} />
<Input
style={{ marginLeft: hp("3%") }}
placeholder='Username'
onChangeText={student_id => setStudentId(student_id)}
returnKeyType={"next"}
blurOnSubmit={false}
onSubmitEditing={el => passwordRef.current = el}
onFocus={() => setShowLogo(false)} />
</Item>
<Item rounded style={{ borderColor: "#FF3C48", marginTop: hp("3%") }}>
<FontAwesome name='unlock' style={styles.iconStyle} />
<Input
ref={passwordRef}
style={{ marginLeft: hp("3%") }}
secureTextEntry={true}
placeholder='Password'
onChangeText={password => setPassword(password)}
returnKeyType={"done"}
onFocus={() => setShowLogo(false)} />
</Item>
<Button full danger
style={{ marginTop: hp("3%") }}
onPress={() => {
// check App.js for further process
signInAction({ student_id, password, site_url, database_name });
}}>
{state.sendingRequest ? (<Spinner color='white' />) : (<Text style={{ color: '#ffffff', fontWeight: 'bold', width: '100%', textAlign: 'center', fontSize: hp("2.8%") }}> LOGIN </Text>)}
</Button>
</ScrollView>
</Root>
)
}
Use this passwordRef.current.focus()