Here is my screen component with two textinputs from the link. I have removed some other code that isn't necessary to this issue.
When i choose the date from the popup it appears in the text input but doesnt get validated.
I cannot use the result of DatePicker component as it is , so i am doing some formating and saved to a function getDate.
How would you go about implemnting this ? is there any better way
enter image description here
import React, { useState, useContext, useEffect } from 'react';
import {
StyleSheet,
View,
Text,
TextInput,
TouchableOpacity,
ScrollView,
KeyboardAvoidingView,
Platform,
Image,
} from 'react-native';
import { icons, COLORS, } from '../constants';
import { Formik } from 'formik';
import * as yup from "yup";
import client from '../api/client';
import DateTimePickerModal from "react-native-modal-datetime-picker";
const addfarm = ({ navigation, Arrival_Date }) => {
const addFarmValidationSchema = yup.object().shape({
Farm_Code: yup.string().required('Please Enter the chick price'),
Arrival_Date: yup.string().required('Please Choose a date'),
});
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const [date, setDate] = useState('');
const showDatePicker = () => {
setDatePickerVisibility(true);
};
const hideDatePicker = () => {
setDatePickerVisibility(false);
};
const handleConfirm = (date) => {
hideDatePicker();
setDate(date);
};
const getDate = () => {
let tempDate = JSON.stringify(date).split(/[ ",T,]/);
return date !== ''
? `${tempDate[1]}`
: '';
};
const newDate = getDate();
const addFarmInfo = {
Farm_Code: '',
Arrival_Date: '',
};
const add = async (values) => {
const res = await client({
method: 'POST',
url: '/Farm/SaveFarm',
data: JSON.stringify({ ...values, id })
})
.then(res => console.log(res.data))
.catch(err => console.log(err))
}
return (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}
style={{ flex: 1 }}>
<ScrollView style={styles.container}>
<Formik
initialValues={addFarmInfo}
validateOnMount={true}
onSubmit={add}
validationSchema={addFarmValidationSchema}>
{({
handleChange,
handleBlur,
handleSubmit,
values,
touched,
errors,
isValid,
setFieldValue,
}) => {
const {
Farm_Code,
Arrival_Date,
} = values
return (
<View
style={{
paddingHorizontal: '10%',
paddingTop: 50,
marginTop: 50,
backgroundColor: COLORS.main_background,
}}>
<Text style={styles.auth_text}>Add Farm</Text>
<Text style={styles.tag}>
Farm Code:
</Text>
<View
style={[styles.textInputView, { marginBottom: 10 }]}>
<TextInput
onChangeText={handleChange('Farm_Code')}
onBlur={handleBlur('Farm_Code')}
value={Farm_Code}
placeholder="Farm Code"
placeholderTextColor={COLORS.placeholder_fonts}
selectionColor={COLORS.drawer_button}
style={styles.textInput}
/>
<Image
source={!errors.Farm_Code ? icons.tick : icons.close}
resizeMode="stretch"
style={{
width: 18,
height: 18,
tintColor: !errors.Farm_Code ? COLORS.drawer_button : 'red',
alignItems: 'center',
marginRight: 10,
}}
/>
</View>
{(errors.Farm_Code && touched.Farm_Code) &&
<Text style={styles.errors}>{errors.Farm_Code}</Text>
}
<Text style={styles.tag}>
Arrival Date:
</Text>
<View
style={[styles.textInputView, { marginBottom: 10 }]}>
<TextInput
onChangeText={handleChange('Arrival_Date')}
onBlur={handleBlur('Arrival_Date')}
value={newDate}
onFocus={showDatePicker}
placeholder="yyyy/mm/dd"
placeholderTextColor={COLORS.placeholder_fonts}
selectionColor={COLORS.drawer_button}
style={styles.textInput}
/>
<TouchableOpacity style={{ marginRight: 10, }}
onPress={showDatePicker}
>
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
onConfirm={handleConfirm}
onCancel={hideDatePicker}
/>
<Image
source={icons.calendar}
resizeMode="stretch"
style={{
width: 18,
height: 18,
tintColor: COLORS.secondary_fonts,
alignItems: 'center'
}}
/>
</TouchableOpacity>
<Image
source={!errors.Arrival_Date ? icons.tick : icons.close}
resizeMode="stretch"
style={{
width: 18,
height: 18,
tintColor: !errors.Arrival_Date ? COLORS.drawer_button : 'red',
alignItems: 'center',
marginRight: 10,
}}
/>
</View>
{(errors.Arrival_Date && touched.Arrival_Date) &&
<Text style={styles.errors}>{errors.Arrival_Date}</Text>
}
{(errors.Arrival_Date && touched.Arrival_Date) &&
<Text style={styles.errors}>{errors.Arrival_Date}</Text>
}
{/* Save */}
<TouchableOpacity
disabled={!isValid}
onPress={handleSubmit}
style={[styles.button, { backgroundColor: isValid ? COLORS.authButtons : COLORS.placeholder_fonts, marginTop: 10 }]}>
<Text style={styles.button_Text}>Save</Text>
</TouchableOpacity>
</View>
)
}
}
</Formik >
</ScrollView>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: COLORS.main_background,
},
textInput: {
flex: 1,
paddingLeft: 10,
color: 'black',
},
auth_text: {
fontSize: 20,
fontWeight: 'bold',
textAlign: 'center',
marginBottom: 5,
},
button: {
height: 50,
width: '100%',
marginVertical: 20,
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center',
},
button_Text: {
fontSize: 18,
color: COLORS.white,
},
login_nav: {
fontSize: 12,
textAlign: 'center',
fontWeight: '400',
marginTop: 10,
},
errors: {
fontSize: 14,
color: 'red',
fontWeight: '400',
marginTop: 5,
},
textInputView: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderRadius: 10,
height: 50,
width: '100%',
borderColor: COLORS.secondary_fonts,
},
tag: {
color: 'black',
fontSize: 15,
marginBottom: 4,
marginLeft: 4
},
});
export default addfarm;
If you want formik to handle the validation, you should call the setFieldValue method and it will trigger the validation as the documentation says
Related
I need help with this, I'm stuck
This is my custom component DataSlideInput.js
and the debugger gives me TypeError: undefined is not a function in every call to any custom component. Like or
import React from 'react';
import {View, Text, TouchableOpacity, StyleSheet} from 'react-native';
import {Colors} from './colors.js';
import {TextInput} from 'react-native-paper';
import {CheckBox, Icon} from '#rneui/themed';
import {useNavigation} from '#react-navigation/core';
import Toast from 'react-native-simple-toast';
import {setUsername, setPassword, setRememberMe} from '../redux/loginSlice';
import {useSelector, useDispatch} from 'react-redux';
const DataSlideInput = props => {
const userName = useSelector(state => state.login.userName);
const password = useSelector(state => state.login.password);
const dispatch = useDispatch();
return (
<TextInput
theme={{roundness: 30}}
placeholder={props.placeholder}
placeholderTextColor={Colors.placeholderColor}
autoCapitalize="none"
mode="outlined"
label={props.label}
secureTextEntry={props.secureTextEntry ? true : false}
outlineColor={Colors.secondary}
activeOutlineColor={Colors.secondary}
style={styles.dataSlideInput}
value={props.label == 'Email' ? userName : password}
onChangeText={value => {
if (props.label == 'Email') {
dispatch(setUsername(value));
}
if (props.label == 'Password') {
dispatch(setPassword(value));
}
}}
/>
);
};
const RememberMe = () => {
const dispatch = useDispatch();
const rememberMe = useSelector(state => state.login.rememberMe);
return (
<View style={styles.rememberMe}>
<CheckBox
checkedIcon={
<Icon
name="radio-button-checked"
type="material"
color={Colors.secondary}
size={25}
iconStyle={{marginRight: 10}}
/>
}
uncheckedIcon={
<Icon
name="radio-button-unchecked"
type="material"
color={Colors.secondary}
size={25}
iconStyle={{marginRight: 10}}
/>
}
checked={rememberMe}
onPress={() => {
dispatch(setRememberMe(!rememberMe));
}}
/>
<Text style={styles.rememberMeText}>Recordarme en este dispositivo</Text>
</View>
);
};
const LogInButton = () => {
const userName = useSelector(state => state.login.userName);
const password = useSelector(state => state.login.password);
const navigation = useNavigation();
const handleSubmit = () => {
if (userName != '' && password != '') {
navigation.navigate('MapaOnline');
} else {
if (userName == '' && password == '')
Toast.show('Por favor, complete E-mail y Contraseña', Toast.SHORT);
else {
if (userName == '')
Toast.show(
'El casillero de E-mail no puede quedar vacio',
Toast.SHORT,
);
if (password == '')
Toast.show('La contraseña no puede ser vacia', Toast.SHORT);
}
}
};
return (
<TouchableOpacity
style={styles.dataSlideLogInButton}
onPress={() => handleSubmit()}>
<Text style={styles.dataSlideLogInButtonText}>Entrar</Text>
</TouchableOpacity>
);
};
const ConfigButton = () => {
const navigation = useNavigation();
return (
<TouchableOpacity
onPress={() => navigation.navigate('Config')}
style={styles.dataSlideConfig}>
<Text style={styles.dataSlideConfigText}>Ir a configuración</Text>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
dataSlideInput: {
borderRadius: 35,
backgroundColor: Colors.primary,
width: '80%',
alignSelf: 'center',
margin: 10,
height: 45,
},
rememberMe: {
flexDirection: 'row',
width: '80%',
alignSelf: 'center',
height: 60,
},
rememberMeText: {
fontSize: 17,
alignSelf: 'center',
marginLeft: -20,
marginBottom: 7,
fontFamily: 'sans-serif-condensed',
},
dataSlideLogInButton: {
borderWidth: 1,
borderColor: Colors.secondary,
backgroundColor: Colors.secondary,
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
width: '80%',
height: 50,
borderRadius: 35,
},
dataSlideLogInButtonText: {
fontSize: 17,
fontWeight: 'bold',
color: Colors.primary,
},
dataSlideConfig: {
marginTop: 10,
alignSelf: 'center',
},
dataSlideConfigText: {
fontFamily: 'sans-serif-condensed',
alignSelf: 'center',
fontSize: 17,
color: Colors.headerColor,
},
});
export {DataSlideInput, RememberMe, LogInButton, ConfigButton};
And I'm trying to put it here. This was working before, but this morning stop...
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* Generated with the TypeScript template
* https://github.com/react-native-community/react-native-template-typescript
*
* #format
*/
import 'react-native-gesture-handler';
import React, {useEffect} from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
Image,
View,
ImageBackground,
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import {Colors} from '../component/colors';
import {useDispatch} from 'react-redux';
import {createTable, getDataFromDB} from '../Database/databaseConfig';
import {
DataSlideInput,
RememberMe,
LogInButton,
ConfigButton,
} from '../component/DataSlideInput';
//configuration -> loading
// related items -> elements or files
const currentRow = ''; //activities detailedInformation relatedItems editedElements connectedElements
const Login = () => {
const dispatch = useDispatch();
useEffect(() => {
createTable();
getDataFromDB(dispatch);
}, []);
return (
<SafeAreaView style={styles.backgroundStyle}>
<ImageBackground
source={require('../component/icons/background.jpg')}
resizeMode="cover"
style={{flex: 1}}>
<Text style={styles.headerText}>ISMobile</Text>
<Image
style={styles.companyLogo}
source={require('../component/icons/logo.png')}
/>
<View style={{flex: 1, justifyContent: 'flex-end'}}>
<Animatable.View animation="fadeInUp" style={styles.dataSlide}>
<Text style={styles.dataSlideHeader}>
Ingresá tus datos para continuar.
</Text>
<DataSlideInput
placeholder="Email"
label="Email"
secureTextEntry={false}
/>
<DataSlideInput
placeholder="Password"
label="Password"
secureTextEntry={true}
/>
<RememberMe />
{/* Clicking LogIn button redirects to mapaOnline */}
<LogInButton />
{/* Clicking Config button redirects to config */}
<ConfigButton />
</Animatable.View>
</View>
</ImageBackground>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
headerText: {
color: Colors.primary,
textAlign: 'center',
fontSize: 20,
marginTop: 25,
fontWeight: 'bold',
},
backgroundStyle: {
flex: 1,
height: '100%',
backgroundColor: Colors.secondary,
justifyContent: 'space-between',
},
companyLogo: {
marginTop: 60,
alignSelf: 'center',
width: 100,
height: 100,
},
dataSlide: {
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
paddingHorizontal: 20,
paddingVertical: 30,
width: '100%',
height: '70%',
backgroundColor: Colors.primary,
},
dataSlideHeader: {
fontFamily: 'sans-serif-condensed',
alignSelf: 'center',
fontSize: 20,
marginBottom: 15,
},
dataSlideConfig: {
marginTop: 10,
alignSelf: 'center',
},
dataSlideConfigText: {
fontFamily: 'sans-serif-condensed',
alignSelf: 'center',
fontSize: 17,
color: Colors.headerColor,
},
});
export default Login;
{
/* <TouchableOpacity
onPress={() => navigation.navigate(currentRow)}
style={{
marginTop: 10,
alignSelf: "center",
}}>
<Text style={{
fontFamily: "sans-serif-condensed",
alignSelf: 'center',
fontSize: 17,
color: Colors.headerColor
}}>debug</Text>
</TouchableOpacity> */
}
Terminal Error
If anyone knows how to fix it, I would be very grateful.
The problem was the version of react-redux.
I installed a previous version and it solved the problem
npm install react-redux#7.0.2
enter image description here Iam new with react native,so maybe my question seems silly to all excepts.I want to add current time in text input.(i designd todo app,that show the todo list,now i want to show time in todo list,for eg i enter todo(complete frontend)and add,that contain complete and delete button,now i want to add time in that(task adding time).my code are following below,
import React from 'react';
import {
StyleSheet,
SafeAreaView,
View,
TextInput,
Text,
FlatList,
TouchableOpacity,
Alert,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
const COLORS = {primary: '#1f145c', white: '#fff'};
const App = () => {
const \[todos, setTodos\] = React.useState(\[\]);
const \[textInput, setTextInput\] = React.useState('');
React.useEffect(() => {
getTodosFromUserDevice();
}, \[\]);
React.useEffect(() => {
saveTodoToUserDevice(todos);
}, \[todos\]);
const addTodo = () => {
if (textInput == '') {
Alert.alert('Error', 'Please input todo');
} else {
const newTodo = {
id: Math.random(),
task: textInput,
completed: false,
};
setTodos(\[...todos, newTodo\]);
setTextInput('');
}
};
const saveTodoToUserDevice = async todos => {
try {
const stringifyTodos = JSON.stringify(todos);
await AsyncStorage.setItem('todos', stringifyTodos);
} catch (error) {
console.log(error);
}
};
const getTodosFromUserDevice = async () => {
try {
const todos = await AsyncStorage.getItem('todos');
if (todos != null) {
setTodos(JSON.parse(todos));
}
} catch (error) {
console.log(error);
}
};
const markTodoComplete = todoId => {
const newTodosItem = todos.map(item => {
if (item.id == todoId) {
return {...item, completed: true};
}
return item;
});
setTodos(newTodosItem);
};
const deleteTodo = todoId => {
const newTodosItem = todos.filter(item => item.id != todoId);
setTodos(newTodosItem);
};
const clearAllTodos = () => {
Alert.alert('Confirm', 'Clear todos?', \[
{
text: 'Yes',
onPress: () => setTodos(\[\]),
},
{
text: 'No',
},
\]);
};
const ListItem = ({todo}) => {
return (
<View style={styles.listItem}>
<View style={{flex: 1}}>
<Text
style={{
fontWeight: 'bold',
fontSize: 20,
color: COLORS.primary,
textDecorationLine: todo?.completed ? 'line-through' : 'none',
}}>
{todo?.task}
</Text>
</View>
{!todo?.completed && (
<TouchableOpacity onPress={() => markTodoComplete(todo.id)}>
<View style={\[styles.actionIcon, {backgroundColor: 'green'}\]}>
<Icon name="done" size={20} color="white" />
</View>
</TouchableOpacity>
)}
<TouchableOpacity onPress={() => deleteTodo(todo.id)}>
<View style={styles.actionIcon}>
<Icon name="delete" size={20} color="white" />
</View>
</TouchableOpacity>
</View>
);
};
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: 'white',
}}>
<View style={styles.header}>
<Text
style={{
fontWeight: 'bold',
fontSize: 20,
color: COLORS.primary,
}}>
TODO APP
</Text>
<Icon name="delete" size={25} color="red" onPress={clearAllTodos} />
</View>
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{padding: 20, paddingBottom: 100}}
data={todos}
renderItem={({item}) => <ListItem todo={item} />}
/>
<View style={styles.footer}>
<View style={styles.inputContainer}>
<TextInput
value={textInput}
placeholder="Add Todo"
onChangeText={text => setTextInput(text)}
/>
</View>
<TouchableOpacity onPress={addTodo}>
<View style={styles.iconContainer}>
<Icon name="add" color="white" size={30} />
</View>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
footer: {
position: 'absolute',
bottom: 0,
width: '100%',
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
backgroundColor: COLORS.white,
},
inputContainer: {
height: 50,
paddingHorizontal: 20,
elevation: 40,
backgroundColor: COLORS.white,
flex: 1,
marginVertical: 20,
marginRight: 20,
borderRadius: 30,
},
iconContainer: {
height: 50,
width: 50,
backgroundColor: COLORS.primary,
elevation: 40,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
},
listItem: {
padding: 20,
backgroundColor: COLORS.white,
flexDirection: 'row',
elevation: 12,
borderRadius: 7,
marginVertical: 10,
},
actionIcon: {
height: 25,
width: 25,
backgroundColor: COLORS.white,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red',
marginLeft: 5,
borderRadius: 3,
},
header: {
padding: 20,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
});
export default App;][1]
i got the answer ,answer is following below,
import React from 'react';
import {
StyleSheet,
SafeAreaView,
View,
TextInput,
Text,
FlatList,
TouchableOpacity,
Alert,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
const COLORS = {primary: '#1f145c', white: '#fff'};
const App = () => {
const [todos, setTodos] = React.useState([]);
const [textInput, setTextInput] = React.useState('');
React.useEffect(() => {
getTodosFromUserDevice();
}, []);
React.useEffect(() => {
saveTodoToUserDevice(todos);
}, [todos]);
const addTodo = () => {
if (textInput == '') {
Alert.alert('Error', 'Please input todo');
} else {
const newTodo = {
id: Math.random(),
task: textInput,
completed: false,
time: getCurrentTime()
};
setTodos([...todos, newTodo]);
setTextInput('');
}
};
const saveTodoToUserDevice = async todos => {
try {
const stringifyTodos = JSON.stringify(todos);
await AsyncStorage.setItem('todos', stringifyTodos);
} catch (error) {
console.log(error);
}
};
const getTodosFromUserDevice = async () => {
try {
const todos = await AsyncStorage.getItem('todos');
if (todos != null) {
setTodos(JSON.parse(todos));
}
} catch (error) {
console.log(error);
}
};
***const getCurrentTime = () => {
let today = new Date();
let date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
let time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
let dateTime = date + '/' + time;
return dateTime;
}***
const markTodoComplete = todoId => {
const newTodosItem = todos.map(item => {
if (item.id == todoId) {
return {...item, completed: true};
}
return item;
});
setTodos(newTodosItem);
};
const deleteTodo = todoId => {
const newTodosItem = todos.filter(item => item.id != todoId);
setTodos(newTodosItem);
};
const clearAllTodos = () => {
Alert.alert('Confirm', 'Clear todos?', [
{
text: 'Yes',
onPress: () => setTodos([]),
},
{
text: 'No',
},
]);
};
const comdel = () => {
Alert.alert('select status', 'Complete or Delete', [
{
text: 'Delete',
onPress: () => setTodos([]),
},
{
text: 'Complete',
onPress: () => {markTodoComplete(todo.id)}
},
]);
};
const ListItem = ({todo}) => {
return (
<View style={styles.listItem}>
<View style={{flex: 1}}>
<Text
style={{
fontWeight: 'bold',
fontSize: 20,
color: COLORS.primary,
textDecorationLine: todo?.completed ? 'line-through' : 'none',
}}>
{todo?.task}
</Text>
</View>
{/* {!todo?.completed && (
<TouchableOpacity onPress={() => markTodoComplete(todo.id)}>
<View style={[styles.actionIcon, {backgroundColor: 'green'}]}>
<Icon name="done" size={20} color="white" />
</View>
</TouchableOpacity>
)} */}
{/* <TouchableOpacity onPress={() => deleteTodo(todo.id)}>
<View style={styles.actionIcon}>
<Icon name="delete" size={20} color="white" />
</View>
</TouchableOpacity> */}
<View>
<Text>
{todo?.time}
</Text>
</View>
<Icon name="menu" size={40} color="#a9a9a9" onPress={comdel} />
</View>
);
};
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: 'white',
}}>
<View style={styles.header}>
<Text
style={{
fontWeight: 'bold',
fontSize: 20,
color: COLORS.primary,
}}>
TODO APP
</Text>
<Icon name="delete" size={25} color="red" onPress={comdel} />
</View>
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{padding: 20, paddingBottom: 100}}
data={todos}
renderItem={({item}) => <ListItem todo={item} />}
/>
<View style={styles.footer}>
<View style={styles.inputContainer}>
<TextInput
value={textInput}
placeholder="Add Todo"
onChangeText={text => setTextInput(text)}
/>
</View>
<TouchableOpacity onPress={addTodo}>
<View style={styles.iconContainer}>
<Icon name="add" color="white" size={30} />
</View>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
footer: {
position: 'absolute',
bottom: 0,
width: '100%',
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
backgroundColor: COLORS.white,
},
inputContainer: {
height: 50,
paddingHorizontal: 20,
elevation: 40,
backgroundColor: COLORS.white,
flex: 1,
marginVertical: 20,
marginRight: 20,
borderRadius: 30,
},
iconContainer: {
height: 50,
width: 50,
backgroundColor: COLORS.primary,
elevation: 40,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
},
listItem: {
padding: 40,
backgroundColor: "#d3d3d3",
flexDirection: 'column',
elevation: 12,
borderRadius: 7,
marginVertical: 10,
},
actionIcon: {
height: 25,
width: 25,
backgroundColor: COLORS.white,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red',
marginLeft: 5,
borderRadius: 3,
},
header: {
padding: 20,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
});
export default App;
I have a sectionlist with an ActivityIndicator at the footer. The ActivityIndicator doesn't go away even after the list has rendered every item. The data is local data.
I do know that I have to use React Hook, so I created _handleLoadMore() to update the state, but I don't know how to detect once the list has come to the end.
This is my code
import React, {useState, useEffect} from 'react';
import {
View,
Text,
StyleSheet,
SectionList,
ActivityIndicator,
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
export default function TransactionHistoryList({data}: {data: any}) {
const [loadMore, setLoadMore] = useState('true')
const _handleLoadMore = () => {
//what to put here
}
const extractKey = ({
id,
}: {
id: any;
name: any;
accountNumber: any;
type: any;
amount: any;
}) => id;
const renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '94%',
backgroundColor: '#000',
alignSelf: 'center',
}}
/>
);
};
const footerComponent = () => {
if (!_handleLoadMore) return null;
return (
<View
style={{
position: 'relative',
paddingVertical: 20,
borderTopWidth: 1,
marginTop: 10,
marginBottom: 10,
}}>
<ActivityIndicator
animating
size="small"
color="#CED0CE"
hidesWhenStopped={true}
/>
</View>
);
};
return (
<SafeAreaView>
<View style={styles.container}>
<Text style={styles.transactionhistory}>Transaction History</Text>
<SectionList
contentContainerStyle={{paddingBottom: 500}}
maxToRenderPerBatch={7}
onEndReachedThreshold={2}
updateCellsBatchingPeriod={4000}
ItemSeparatorComponent={renderSeparator}
sections={data}
renderSectionHeader={({section}) => {
return <Text style={styles.date}>{section.title}</Text>;
}}
renderItem={({item}) => {
return (
<View style={styles.item}>
<Text>
<View>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.accountNumber}>
{item.accountNumber}
</Text>
</View>
</Text>
<View style={styles.amountContainer}>
<Text
style={[
item.type == 'in' ? styles.moneyIn : styles.moneyOut,
]}>
{item.amount}
</Text>
</View>
</View>
);
}}
ListFooterComponent= {footerComponent}
keyExtractor={extractKey}
/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
marginLeft: 20,
marginRight: 20,
marginTop: 120,
flex: -200,
//paddingBottom: 10
},
transactionhistory: {
fontWeight: 'bold',
fontSize: 18,
paddingBottom: 10,
paddingLeft: 25,
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
marginRight: 20,
marginLeft: 25,
paddingBottom: 10,
paddingTop: 10,
},
date: {
padding: 10,
marginBottom: 15,
backgroundColor: '#e0e0e0',
fontFamily: 'OpenSans-Bold',
fontSize: 15,
paddingLeft: 25,
},
name: {
fontSize: 14,
fontFamily: 'OpenSans-SemiBold',
},
accountNumber: {
fontSize: 12,
fontFamily: 'OpenSans-Regular',
},
amountContainer: {
paddingTop: 8,
},
moneyIn: {
color: '#689f38',
letterSpacing: 0.8,
fontSize: 16,
fontFamily: 'OpenSans-SemiBold',
},
moneyOut: {
color: '#b71c1c',
letterSpacing: 0.8,
fontSize: 16,
fontFamily: 'OpenSans-SemiBold',
},
loading: {
color: '#CED0CE',
},
});
section-list support on-scroll event and you can can hide/show activity-indicator feature quite smoothly with on scroll
Example:
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};
<SectionList
contentContainerStyle={{paddingBottom: 500}}
maxToRenderPerBatch={7}
onEndReachedThreshold={2}
onScroll={({nativeEvent}) => {
if (isCloseToBottom(nativeEvent)) {
if(!this.state.fetching_status){
//what you want to do when the screen reached end of screen
//console.log or something usefull
}
}
}}
.../>
I think it is possible to use onEndReached prop of SectionList in your case https://reactnative.dev/docs/sectionlist#onendreached
That is the correct place to write your logic to load next "page" of your items
Problem:
I have created react native camera but it is looked like this.
But the problem is the background color of camera action icons are transparent.
This is my code.
import React, {useState, useEffect} from 'react';
import {
AppRegistry,
StyleSheet,
TouchableOpacity,
View,
Image,
CameraRoll,
Platform,
} from 'react-native';
import IoniconsIcon from 'react-native-vector-icons/Ionicons';
import EntypoIcon from 'react-native-vector-icons/Entypo';
import AppText from '_components/appText';
import {RNCamera} from 'react-native-camera';
import normalize from '_utils/fontsize';
let countRecordTime;
const PendingView = () => (
<View
style={{
flex: 1,
backgroundColor: 'lightgreen',
justifyContent: 'center',
alignItems: 'center',
}}>
<AppText>Waiting</AppText>
</View>
);
const takePicture = async (camera) => {
const options = {quality: 1};
const data = await camera.takePictureAsync(options);
console.log(data.uri);
};
const recordVideo = async (
camera,
recording,
seconds,
setRecording,
setSeconds,
) => {
if (camera) {
if (!recording) {
startRecording(recording, setRecording, seconds, setSeconds, camera);
} else {
stopRecording(camera, setSeconds);
}
}
};
const startRecording = async (
recording,
setRecording,
seconds,
setSeconds,
camera,
) => {
setRecording(true);
console.log('>>>>>> start recording seconds', seconds);
const cameraConfig = {maxDuration: 20};
const data = await camera.recordAsync(cameraConfig);
console.log('>>>>>> data', data);
setRecording(false);
};
const stopRecording = (camera, setSeconds) => {
camera.stopRecording();
setSeconds(0);
};
const secondsToMMSS = (seconds) => {
console.log('>>>>>> seconds', seconds);
let m = Math.floor(seconds / 60);
let s = Math.floor(seconds % 60);
let mDisplay = m < 10 ? `0${m}` : `${m}`;
let sDisplay = s < 10 ? `0${s}` : `${s}`;
return `${mDisplay}:${sDisplay}`;
};
const VideoRecording = (props) => {
const [type, setType] = useState(RNCamera.Constants.Type.back);
const [flashMode, setFlashMode] = useState(RNCamera.Constants.FlashMode.off);
const [recording, setRecording] = useState(false);
const [seconds, setSeconds] = useState(0);
useEffect(() => {
if (recording) {
countRecordTime = setInterval(() => setSeconds(seconds + 1), 1000);
}
if (!recording && countRecordTime) {
clearInterval(countRecordTime);
}
if (seconds === 20 && countRecordTime) {
clearInterval(countRecordTime);
setRecording(false);
}
return () => {
if (countRecordTime) {
clearInterval(countRecordTime);
}
};
}, [recording, seconds]);
return (
<View style={styles.container}>
<RNCamera
style={styles.preview}
autoFocus={RNCamera.Constants.AutoFocus.on}
type={type}
flashMode={flashMode}
faceDetectionMode={RNCamera.Constants.FaceDetection.Mode.fast}
ratio="4:3"
whiteBalance={RNCamera.Constants.WhiteBalance.auto}
captureAudio={true}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
androidRecordAudioPermissionOptions={{
title: 'Permission to use audio recording',
message: 'We need your permission to use your audio',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}>
{({camera, status, recordAudioPermissionStatus}) => {
if (status !== 'READY') {
return <PendingView />;
}
return (
<>
<View
style={{
flex: 0,
flexDirection: 'row',
justifyContent: 'center',
}}>
<TouchableOpacity
style={styles.capture}
onPress={(_) => {
switch (flashMode) {
case RNCamera.Constants.FlashMode.off:
setFlashMode(RNCamera.Constants.FlashMode.auto);
break;
case RNCamera.Constants.FlashMode.auto:
setFlashMode(RNCamera.Constants.FlashMode.on);
break;
case RNCamera.Constants.FlashMode.on:
setFlashMode(RNCamera.Constants.FlashMode.off);
break;
}
}}>
<Image
source={
flashMode === RNCamera.Constants.FlashMode.auto
? require('../../assets/img/flashAuto.png')
: flashMode === RNCamera.Constants.FlashMode.on
? require('../../assets/img/flashOn.png')
: require('../../assets/img/flashOff.png')
}
style={{width: 30, height: 30}}
resizeMode={'contain'}
/>
</TouchableOpacity>
{/* <TouchableOpacity
onPress={() => takePicture(camera)}
style={styles.capture}>
<Image
source={require('../../assets/img/cameraButton.png')}
style={{width: 50, height: 50}}
resizeMode={'contain'}
/>
</TouchableOpacity> */}
<TouchableOpacity
style={styles.iconContainer}
onPress={() =>
recordVideo(
camera,
recording,
seconds,
setRecording,
setSeconds,
)
}>
<EntypoIcon
style={styles.icon}
size={40}
color={recording ? 'red' : 'white'}
name="video-camera"
/>
{recording ? (
<AppText styles={styles.recordingTime}>
{secondsToMMSS(seconds)}
</AppText>
) : null}
</TouchableOpacity>
<TouchableOpacity
style={styles.capture}
onPress={(_) => {
if (type === RNCamera.Constants.Type.back) {
setType(RNCamera.Constants.Type.front);
} else {
setType(RNCamera.Constants.Type.back);
}
}}>
<Image
source={require('../../assets/img/cameraFlipIcon.png')}
style={{width: 40, height: 40}}
resizeMode={'contain'}
/>
</TouchableOpacity>
</View>
<TouchableOpacity style={styles.closeButton} onPress={() => {}}>
<IoniconsIcon
name={'ios-close'}
style={styles.closeButtonIcon}
/>
</TouchableOpacity>
</>
);
}}
</RNCamera>
</View>
);
};
export default VideoRecording;
const styles = StyleSheet.create({
container: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
backgroundColor: 'black',
},
capture: {
flex: 0,
borderRadius: 5,
padding: 15,
paddingHorizontal: 20,
alignSelf: 'center',
margin: 20,
},
cptureView: {
backgroundColor: '#ffffff',
width: 100,
height: 100,
borderRadius: 100,
alignItems: 'center',
justifyContent: 'center',
marginBottom: '20%',
marginTop: '5%',
},
camIcon: {
color: '#858181',
},
iconContainer: {
justifyContent: 'center',
alignItems: 'center',
},
icon: {
marginHorizontal: 15,
// paddingVertical: 10,
},
recordingTime: {
color: 'red',
},
closeButton: {
position: 'absolute',
backgroundColor: '#aaaaaab0',
width: 50,
height: 50,
borderRadius: 25,
justifyContent: 'center',
top: Platform.OS === 'ios' ? 45 : 10,
left: 10,
},
closeButtonIcon: {
fontSize: Platform.OS === 'ios' ? 40 : 40,
fontWeight: 'bold',
alignSelf: 'center',
lineHeight: Platform.OS === 'ios' ? 58 : 40,
},
});
Can someone help me to make it black? I tried a lot to find out way to do so that. But I could not so if someone can help me it would be grateful. Thank you very much.
Have you try this?
...
<View
style={{
flex: 0,
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: "#000000", //-----------------Here?
}}>
<TouchableOpacity
style={styles.capture}
onPress={(_) => {
switch (flashMode) {
case RNCamera.Constants.FlashMode.off:
setFlashMode(RNCamera.Constants.FlashMode.auto);
...
My code seems to be good but I do not understand why it is just doing nothing when I hit the "X" look at the code below please and help me out!
import React, { useState } from 'react';enter code here
import { StyleSheet, FlatList, Text, View, Image, TextInput, Button, Keyboard, TouchableOpacity, CheckBox } from 'react-native';
import Interactable from 'react-native-interactable';
export default function App() {
const [enteredGoal, setEnteredGoal] = useState('');
const [courseGoals, setCourseGoals] = useState([]);
const goalInputHandler = (enteredText) => {
setEnteredGoal(enteredText);
};
const addGoalHandler = () => {
if (enteredGoal.length > 0) {
setCourseGoals(currentGoals => [...currentGoals, enteredGoal])
} else {
alert("You have to write something!")
}
}
const deleteItem = idx => {
const clonedGoals = [...courseGoals]
courseGoals.splice(idx, 1)
setCourseGoals(courseGoals)
}
return (
<View style={styles.container}>
<View style={styles.topPart}></View>
<View style={styles.navBar}>
<Image source={require('./assets/baseline_menu_black_18dp.png/')} />
<Text style={styles.heading}> Grocery List </Text>
</View>
<View style={styles.body}>
<TextInput
style={styles.textInput}
placeholder='Groceries'
maxLength={20}
onBlur={Keyboard.dismiss}
value={enteredGoal}
onChangeText={goalInputHandler}
/>
<View style={styles.inputContainer}>
<TouchableOpacity style={styles.saveButton}>
<Button title="ADD" onPress={addGoalHandler} color="#FFFFFF" style={styles.saveButtonText} />
</TouchableOpacity>
</View>
<View style={styles.container}>
<FlatList
data={courseGoals}
renderItem={(itemData, idx) => (
<View style={styles.groceryItem} >
<Text style={styles.groceryItemText}>{itemData.item}</Text>
<Text style={styles.groceryItemDelete} onPress={() => deleteItem(idx)}>X</Text>
</View>
)}
/>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
topPart: {
height: '3%',
backgroundColor: '#5498A7',
},
navBar: {
height: '10%',
backgroundColor: '#5498A7',
elevation: 3,
paddingHorizontal: 15,
flexDirection: 'row',
alignItems: 'center',
},
body: {
backgroundColor: '#edebe9',
height: '100%',
flex: 1
},
heading: {
fontWeight: "bold",
justifyContent: 'center',
paddingLeft: '13%',
fontSize: 25,
color: '#d6d4d3'
},
textInput: {
borderColor: '#CCCCCC',
borderTopWidth: 1,
borderBottomWidth: 1,
height: 50,
fontSize: 25,
paddingLeft: 20,
paddingRight: 20
},
saveButton: {
borderWidth: 1,
borderColor: '#5498A7',
backgroundColor: '#5498A7',
padding: 15,
margin: 5,
},
saveButtonText: {
color: '#FFFFFF',
fontSize: 20,
textAlign: 'center'
},
groceryItem: {
borderWidth: 1,
borderColor: 'black',
backgroundColor: '#6A686B',
padding: 15,
margin: 5,
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between'
},
groceryItemText: {
color: '#d6d4d3',
},
groceryItemDelete: {
color: 'red',
fontWeight: 'bold',
fontSize: 20
}
});
I am just a beginner and am trying to figure out how to make this work better, if you have an idea please say how to fix it I would really appreciate it. This is a project I am doing just to get started with the learning process but this has been taking a bit longer than expected. Thank you!
I guess you have to change deleteItem function as following.
const deleteItem = idx => {
const clonedGoals = [...courseGoals]
clonedGoals.splice(idx, 1)
setCourseGoals(clonedGoals)
}
You have to replace courseGoals with clonedGoals
You can use ES2015 to achieve it in fewer lines, update your delete function like this:
const deleteItem = element => {
const clonedGoals = courseGoals.filter((item) => item !== element);
setCourseGoals(clonedGoals);
}
also update your onPress instead of passing index pass the item itself like this
onPress={() => deleteItem(itemData.item)}