I'm new to React Native, and I'm following along with an online tutorial.
This is my App.js file:
import React, { useState, useEffect } from 'react';
import {View,Text,ImageBackground,FlatList, Image, TouchableHighlight } from 'react-native';
import bookmarkIcon from './assets/bookmark.png';
import readIcon from './assets/read.png';
import styles from './styles';
const ArticleItem = ({article}) => {
const { title, description, url, urlToImage } = article;
return (
<View style = { styles.articleContainer }>
<Image style={ styles.articleImage } source={{ uri: urlToImage }} />
<Text style= { styles.articleTitle }>
{ title }
</Text>
<Text style = { styles.articleDescription }>
{ description }
</Text>
<View style = { styles.articleBtns}>
<IconButton width= "50%" color = "white" bgcolor = "#ff5c5c" icon = { readIcon } onPress = { () => { console.log("Button pressed!")} } title = "Open" />
<IconButton width= "50%" color = "white" bgcolor = "#ff5c5c" icon = { bookmarkIcon } onPress = { () => { console.log("Button pressed!")} } title = "Read later" />
</View>
</View>
)
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
FlatListHeader = () => {
return (
<View elevation={1}
style={{
height: 100,
width: "97%",
margin: 5,
backgroundColor: "#fff",
border: 2.9,
borderColor: "black",
alignSelf: "center",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 16,
},
shadowOpacity: 1,
shadowRadius: 7.49
}}
>
<Text style={{
textShadowColor: 'black',
textShadowOffset: { width: 1, height: 3 },
textShadowRadius: 10,
fontSize: 40,
fontWeight: '800',
flex: 1,
alignSelf: "center",
paddingTop: 30
}}
>Latest articles</Text>
</View>
);
}
const IconButton = ({title, color, bgcolor, onPress, width, icon }) =>{
return (
<TouchableHighlight onPress = { onPress } style= { { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: bgcolor } }>
<View style={ {width: width, flexDirection: 'row', justifyContent: 'center', alignItems: 'center' } }>
<Image style = { { height: 27, width:27, margin : 5 } } source = { icon }></Image>
<Text style = { {color: color }} > { title } </Text>
</View>
</TouchableHighlight>
);
}
const HomeScreen = (props) => {
console.log("articles: ", props.articles);
return (
<View>
<FlatList
data={ props.articles }
ListHeaderComponent = { this.FlatListHeader }
ItemSeparatorComponent = { this.FlatListItemSeparator}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) => <ArticleItem article = { item } />}
/>
</View>
);
}
const SplashScreen = (props) => {
return (
<View style = { styles.container } >
<ImageBackground style= { styles.backgroundImage } source={{uri: 'http://i.imgur.com/IGlBYaC.jpg'}} >
<View style= { styles.logoContainer }>
<Text style = { styles.logoText }>
Newzzz
</Text>
<Text style = { styles.logoDescription }>
Get your doze of daily news!
</Text>
</View>
</ImageBackground>
</View>
);
}
const App = () => {
const URL = 'https://raw.githubusercontent.com/nimramubashir/React-Native/fetch/articles.json';
const [articles, setArticles] = useState([]);
const [loading, setLoading ] = useState(true);
useEffect(()=>{
fetch(URL)
.then((response) => response.json())
.then((responseJson) => {
return responseJson.articles;
})
.then( articles => {
setArticles(articles);
console.log(articles);
setLoading(false);
})
.catch( error => {
console.error(error);
});
} , []);
if (loading){
return <SplashScreen />
} else {
return <HomeScreen articles = { articles }/>
}
};
export default App
The code is the same as the tutorial, but when I'm trying to run this code, I'm getting an Error
ReferenceError: FlatListItemSeparator is not defined
I've tried to import the FlatListItemSeparator, but since it is read-only, I can't. I'm getting this error at both FlatListItemSeparator and FlatListHeader. Why am I getting this error, and how can I solve it?
you are having each component as separate Function-Component. The tutorial is probably based on Class-Components. In Function-Components there is no this, so just remove the this.
Related
I'm trying to make an app where I can add item in a flatlist . Then each item I can navigate to a new page only for that specific item . In that page, I can add another flatlist.
To explain it more, lets say I add few Classroom item in the flatlist (Classroom A, Classroom B, Classroom C). When I press Clasroom A , it will navigate to a page named Classroom A . In that page, I can add and delete the name of each students using another flatlist.
How can I design the page for the Classsrooms ??? Because when I add the name of the student in classroom A, the names of the students is also available in the flatlist of other Classrooms.
This is my code for the Main Menu:
import React, { useState , useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
FlatList,
Alert,
TextInput,
StyleSheet,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useNavigation } from '#react-navigation/native';
export default function MainMenu(){
const [classroomInput, setClassroomInput] = useState('');
const [classroom, setClassroom] = useState([]);
const navigation = useNavigation();
useEffect(() => {
getClassroom();
}, []);
useEffect(() => {
saveClassroom(classroom);
}, [classroom]);
const saveClassroom = async (classroom) => {
try {
const stringifyClassroom = JSON.stringify(classroom);
await AsyncStorage.setItem('classroom', stringifyClassroom);
} catch (error) {
console.log(error);
}
};
const getClassroom = async () => {
try {
const classrooms = await AsyncStorage.getItem('classroom');
if (classrooms !== null) {
setClassroom(JSON.parse(classrooms));
}
} catch (error) {
console.log(error);
}
};
const addClassroom = () => {
if (classroomInput === ''){
Alert.alert('Error', 'Please input class');
} else {
const newClassroom = {
id: Math.random().toString(),
Classroom: classroomInput,
};
setClassroom([...classroom,newClassroom]);
setClassroomInput('');
}
};
const deleteClassroom = (classroomId) => {
const newClassrooms = classroom.filter(item => item.id !== classroomId);
setClassroom(newClassrooms);
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder={'Add Classrooms'}
value={classroomInput}
onChangeText={(text) => setClassroomInput(text)}
/>
<TouchableOpacity onPress={() => addClassroom()} style={styles.button}>
<Text>Add Classroom</Text>
</TouchableOpacity>
<FlatList
style={styles.flatlist}
data={classroom}
keyExtractor = { (item) => item.id.toString() }
renderItem={({ item }) => (
<TouchableOpacity onPress= {() => navigation.navigate('Classroom', item)} >
<View style={styles.listItem}>
<View>
<Text style={[styles.classText , {fontSize: 18}]}>
{item?.Classroom}
</Text>
</View>
<View >
<TouchableOpacity style={[styles.delete ]} onPress={() => deleteClassroom(classroom?.id)}>
<Icon name="remove" size={15} color={'#fff'} />
</TouchableOpacity>
</View>
</View>
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
input: {
width: '70%',
borderBottomWidth: 1,
marginBottom: 20,
},
button: {
backgroundColor: 'lightblue',
padding: 10,
marginBottom: 10,
},
delete: {
backgroundColor: '#ff3333',
padding: 5,
color: '#fff',
borderWidth: 1,
borderColor: '#ff9999',
borderRadius: 5,
},
listItem: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '70%',
alignItems: 'center',
},
});
And this is the code for the classroom:
/* eslint-disable prettier/prettier */
import React, { useState , useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
FlatList,
Alert,
TextInput,
StyleSheet,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
const Classroom = ( {navigation, route}) => {
const [studentInput, setStudentInput] = useState('');
const [student, setStudent] = useState([]);
useEffect(() => {
getStudent();
}, []);
useEffect(() => {
saveStudent(student);
}, [student]);
const saveStudent = async (student) => {
try {
const stringifyStudent = JSON.stringify(student);
await AsyncStorage.setItem('student', stringifyStudent);
} catch (error) {
console.log(error);
}
};
const getStudent = async () => {
try {
const students = await AsyncStorage.getItem('student');
if (students !== null) {
setStudent(JSON.parse(students));
}
} catch (error) {
console.log(error);
}
};
const addStudent = () => {
if (studentInput === ''){
Alert.alert('Error', 'Please input student name');
} else {
const newStudent = {
id: Math.random().toString(),
Name: studentInput,
};
setStudent([...student,newStudent]);
setStudentInput('');
}
};
const deleteStudent = (studentId) => {
const newStudent = student.filter(item => item.id !== studentId);
setStudent(newStudent);
};
return (
<View styles={styles.container}>
<TouchableOpacity onPress={()=> navigation.goBack()} style={styles.button}>
<Text>Back</Text>
</TouchableOpacity>
<Text style={{fontWeight: 'bold', fontSize: 20}}>[ Classroom Name ]</Text>
<TextInput
style={styles.input}
placeholder={'Add Student Name'}
value={studentInput}
onChangeText={(text) => setStudentInput(text)}
/>
<TouchableOpacity onPress={()=> addStudent()} style={styles.button}>
<Text>Add Student</Text>
</TouchableOpacity>
<FlatList
style={styles.flatlist}
data={student}
keyExtractor = { (item) => item.id.toString() }
renderItem={({ item }) => (
<View style={styles.listItem}>
<View>
<Text style={[styles.classText , {fontSize: 18}]}>
{item?.Name}
</Text>
</View>
<View >
<TouchableOpacity style={[styles.delete ]} onPress={() => deleteStudent(item?.id)}>
<Icon name="remove" size={15} color={'#fff'} />
</TouchableOpacity>
</View>
</View>
)}
/>
</View>
);
};
export default Classroom;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
input: {
width: '70%',
borderBottomWidth: 1,
marginBottom: 20,
},
button: {
backgroundColor: 'lightblue',
padding: 10,
marginBottom: 10,
},
listItem: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '70%',
alignItems: 'center',
},
delete: {
backgroundColor: '#ff3333',
padding: 5,
color: '#fff',
borderWidth: 1,
borderColor: '#ff9999',
borderRadius: 5,
},
});
You are using the same AsyncStorage key 'student' regardless of which classroom you are looking at. You need to keep your student lists separate, so you'll need a separate key for each. Something like:
const key = `students_in_room_${classroomId}`
You can get the classroom id (A, B, C) through the route prop from your navigation.
Edit: You would use this unique key instead of the string 'students' for reading and writing to AsyncStorage. That way you can have separate stored values for each classroom.
const students = await AsyncStorage.getItem(key);
await AsyncStorage.setItem(key, stringifyStudent);
i've done the react-native-pdf to show the slides of my pdf file. But, I want to set the current page state to show up on the display. And when the value is set, it'll refresh that screen and goes back to the first page automatically.
this is my code:
import React, { useState } from 'react';
import { StyleSheet, Dimensions, View, Text } from 'react-native';
import Pdf from 'react-native-pdf';
function Work() {
const [currentPage, setCurrentPage] = useState()
const ShowPdf = () => {
const source = { uri: 'http://samples.leanpub.com/thereactnativebook-sample.pdf', cache: true };
return (
<Pdf
source={source}
onLoadComplete={(numberOfPages, filePath) => {
console.log(`number of pages: ${numberOfPages}`);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`current page: ${page}`);
setCurrentPage(page) //set the cuurentPage
}}
onError={(error) => {
console.log(error);
}}
onPressLink={(uri) => {
console.log(`Link presse: ${uri}`)
}}
style={styles.pdf} />
)
}
return (
<View style={styles.container}>
<ShowPdf />
<View style={styles.pageNumber}>
<Text>{currentPage}</Text>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
//marginTop: 25,
//backgroundColor: 'red',
backfaceVisibility: 'hidden'
},
pdf: {
flex: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
pageNumber: {
position: 'absolute',
left: 20,
top: 20,
backgroundColor: 'rgba(173, 173, 173, 0.5)',
padding: 13,
borderRadius: 6,
}
});
export default Work;
my emulator display:
image
Anyway I can fix this?
Instead of use this
<View style={styles.container}>
<ShowPdf />
<View style={styles.pageNumber}>
<Text>{currentPage}</Text>
</View>
</View>
please use it
<View style={styles.container}>
<Pdf
source={{ uri: path }}
onLoadComplete={(numberOfPages, filePath) => {
console.log(`number of pages: ${numberOfPages}`);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`current page: ${page}`);
setCurrentPage(page) //set the cuurentPage
}}
onError={(error) => {
console.log(error);
}}
onPressLink={(uri) => {
console.log(`Link presse: ${uri}`)
}}
style={styles.pdf} />
<View style={styles.pageNumber}>
<Text>{currentPage}</Text>
</View>
</View>
<ShowPdf/> is your custom react component it will be re-rendered for every page change. So, that is why you faced this problem
I want to navigate from my login screen to the home screen without showing the view. I am trying to do is if from the splash screen if it gets the username from async storage then move to login page ...wherein login page by if the username matches from the POST method in login screen directly login if not then show the login screen view
here is my code
import React ,{useState} from 'react';
import {
View,
Text,
TouchableOpacity,
TextInput,
Platform,
StyleSheet ,
StatusBar,
Alert
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import LinearGradient from 'react-native-linear-gradient';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import Feather from 'react-native-vector-icons/Feather';
import { useTheme } from 'react-native-paper';
const asdf = ({navigation}) => {
const STORAGE_KEY = 'username';
const [userName, setUserName ] = useState('');
const [errortext, setErrortext] = useState('');
const retrieveData = async () => {
try {
const value = await AsyncStorage.getItem(STORAGE_KEY);
if (value !== null) {
var str = value;
// str = str.replace(/^"|"$/g, '');
str = str.replace(/"/g,'');
fetchData(str);
}
} catch (error) {
// Error retrieving data
}
};
retrieveData();
const handleSubmitPress = () => {
if (!userName){
setUserName('')
// onChangeText();
return
} else{
fetchData(userName);
}
setUserName('')
//onChangeText();
}
const fetchData = (userName) => {
if(userName){
let dataToSend = {search :userName}
let formBody = [];
for (let search in dataToSend) {
let encodeKey = encodeURIComponent(search);
let encodeValue = encodeURIComponent(dataToSend[search]);
formBody.push(encodeKey + '=' + encodeValue);
}
formBody = formBody.join('&');
fetch('https://qwert/work/rest/apiofficeapp.php', {
method: 'POST', //Request Type
body: formBody, //post body
headers: {
//Header Defination
'Content-Type':
'application/x-www-form-urlencoded;charset=UTF-8',
},
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson[0] != ''){
//alert(JSON.stringify(responseJson[0]));
const saveData = async () => {
try {
await AsyncStorage.setItem(STORAGE_KEY, responseJson[0][0]['username'])
//await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(responseJson[0][0]['username']))
//alert('Data successfully saved login page')
} catch (e) {
//alert('Failed to save the data to the storage')
}
}
saveData();
navigation.navigate('HomeApp');
setErrortext('');
}else {
setErrortext(userName + 'user not found')
}
})
.catch((error) => {
console.error(error);
});
} }
// const onChangeText = userName => setUserName(userName)
const onChangeText = userName => setUserName(userName)
const { colors } = useTheme();
// const onChangeText = (val) => {
// if( val.length !== 0 ) {
// setUserName({
// ...userName,
// userName: val,
// });
// } else {
// setUserName({
// ...userName,
// userName: val,
// });
// }
// }
return (
<View style={styles.container}>
<StatusBar backgroundColor='#009387' barStyle="light-content"/>
<View style={styles.header}>
<Text style={styles.text_header}>Welcome!</Text>
</View>
<Animatable.View
animation="fadeInUpBig"
style={[styles.footer, {
backgroundColor: colors.background
}]}
>
<Text style={[styles.text_footer, {
color: colors.text
}]}>Username</Text>
<View style={styles.action}>
<FontAwesome
name="user-o"
color={colors.text}
size={20}
/>
<TextInput
placeholder="Your Username"
placeholderTextColor="#666666"
style={[styles.textInput, {
color: colors.text
}]}
autoCapitalize="none"
onChangeText={(userName) => onChangeText(userName)}
onSubmitEditing={handleSubmitPress}
/>
</View>
{/* {data.check_textInputChange ?
<Animatable.View
animation="bounceIn"
>
<Feather
name="check-circle"
color="red"
size={20}
/>
</Animatable.View>
: null}
</View> */}
<View>
{errortext != '' ? (
<Text style={styles.errorMsg}>
{errortext}
</Text>
) : null}
</View>
<View style={styles.button}>
<TouchableOpacity
style={styles.signIn}
onPress={() => {handleSubmitPress()}}
>
<LinearGradient
colors={['#eb0c00', '#A80900']}
style={styles.signIn}
>
<Text style={[styles.textSign, {
color:'#fff'
}]}> Sign In </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={() => navigation.navigate('Register')}
style={[styles.signIn, {
borderColor: '#A80900',
borderWidth: 1,
marginTop: 15
}]}
>
<Text style={[styles.textSign, {
color: '#A80900'
}]}> Register </Text>
</TouchableOpacity>
</View>
</Animatable.View>
</View>
);
};
export default asdf;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#A80900'
},
header: {
flex: 1,
justifyContent: 'flex-end',
paddingHorizontal: 20,
paddingBottom: 50
},
footer: {
flex: 3,
backgroundColor: '#fff',
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
paddingHorizontal: 20,
paddingVertical: 30
},
text_header: {
color: '#fff',
fontWeight: 'bold',
fontSize: 30
},
text_footer: {
color: '#05375a',
fontSize: 18
},
action: {
flexDirection: 'row',
marginTop: 10,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
paddingBottom: 5
},
actionError: {
flexDirection: 'row',
marginTop: 10,
borderBottomWidth: 1,
borderBottomColor: '#FF0000',
paddingBottom: 5
},
textInput: {
flex: 1,
marginTop: Platform.OS === 'ios' ? 0 : -12,
paddingLeft: 10,
color: '#05375a',
},
errorMsg: {
color: '#FF0000',
fontSize: 14,
},
button: {
alignItems: 'center',
marginTop: 50
},
signIn: {
width: '100%',
height: 50,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10
},
textSign: {
fontSize: 18,
fontWeight: 'bold'
}
});
I not able to navigate to home app without showing the login screen directly
One thing you can try is to use a Splash lib that will create an actual native screen for the splash and you just dismiss the splash screen on the login screen or the main screen.
One lib you may use:
https://github.com/crazycodeboy/react-native-splash-screen
It fairly simple to install and you just need to call this on your Login or Mais screen when its mounted:
import SplashScreen from 'react-native-splash-screen'
export default class MainPage extends Component {
componentDidMount() {
SplashScreen.hide();
}
}
Success on your project.
store.js
import AsyncStorage from "#react-native-community/async-storage";
import { createStore, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import { createLogger } from "redux-logger";
import thunk from "redux-thunk";
import reducers from "../reducers";
const logger = createLogger({
// ...options
});
const persistedReducer = persistReducer(persistConfig, reducers);
export default () => {
let store = createStore(persistedReducer, {}, applyMiddleware(thunk, logger));
let persistor = persistStore(store);
return { store, persistor };
};
PathexploredTab.js
import * as React from "react";
import {
View,
StyleSheet,
Text,
Dimensions,
TouchableOpacity,
Alert,
Platform,
Image
} from "react-native";
import { TabView, SceneMap, TabBar } from "react-native-tab-view";
import { Config } from "#common";
import { connect } from "react-redux";
import { compose } from "redux";
import { Dropdown } from "react-native-material-dropdown";
import { Field, reduxForm } from "redux-form";
import { ScrollView } from "react-native-gesture-handler";
import { Actions } from "react-native-router-flux";
import Icon from "react-native-vector-icons/Feather";
import {
searchImmipaths,
isKeepData,
backToInitialState,
continueFromPrevious,
fetchDynamicFacts,
pathExplorerTutorial
} from "../actions/path.actions";
import { checkConnection } from "../service/checkConnection";
import Loader from "./Loader";
import { colors, normalize, family, Images } from "#common";
import ResponsiveImage from 'react-native-responsive-image';
import { RFValue } from "react-native-responsive-fontsize";
import RNPicker from "rn-modal-picker";
import * as Animatable from 'react-native-animatable';
import UserinfoPopUp from "./../pages/UserinfoPopUp";
import { updateUserDetails, getUserDetails } from "../actions/auth.actions";
import AsyncStorage from "#react-native-community/async-storage";
import { copilot, walkthroughable, CopilotStep } from 'react-native-copilot';
import { StepNumberComponent } from "./../pages/newProfileScreen";
import persist from "./../config/store";
import Reactotron from 'reactotron-react-native'
const WalkthroughableImage = walkthroughable(Image);
const WalkthroughableText = walkthroughable(Text);
const WalkthroughableView = walkthroughable(View);
const WalkthroughableTouch = walkthroughable(TouchableOpacity);
const persistStore = persist();
const TooltipComponent = ({
isFirstStep,
isLastStep,
handleNext,
handlePrev,
handleStop,
labels,
currentStep,
}) => {
const handleDiscardTutorial = () => {
Alert.alert(
'',
'are you sure you don’t want a tutorial on how to use the app?',
[
{
text: 'yes',
onPress: () => {AsyncStorage.setItem('DontShowTutorial', JSON.stringify(true)), handleStop()}
},
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
},
],
{ cancelable: false }
);
}
return (
<View style={styles.tooltipContainer}>
<Text testID="stepDescription" style={styles.tooltipText}>{currentStep.text}</Text>
<View style={[styles.bottomBar]}>
{
!isFirstStep ?
<TouchableOpacity style={styles.toolTipButton} onPress={handlePrev}>
<Text style={styles.toolTipButtonText}>{'Previous'}</Text>
</TouchableOpacity>
: null
}
{
!isLastStep ?
<TouchableOpacity style={styles.toolTipButton} onPress={handleNext}>
<Text style={styles.toolTipButtonText}>{'Next'}</Text>
</TouchableOpacity> :
<TouchableOpacity style={styles.toolTipButton} onPress={handleStop}>
<Text style={styles.toolTipButtonText}>{'Finish'}</Text>
</TouchableOpacity>
}
<TouchableOpacity onPress={() => persistStore.store.dispatch(pathExplorerTutorial('bbv'))}>
<Text style={styles.toolTipButtonText}>Go</Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleDiscardTutorial}>
<Text style={styles.toolTipButtonText}>Do not show tutorial</Text>
</TouchableOpacity>
</View>
</View>
);
}
const window = Dimensions.get("window");
var width = window.width;
var height = window.height;
var immigrationInterst = [];
var countryIntrest = [];
let countryIntrestNow = [];
var FirstRoute = () => <View style={[{ height: height }]} />;
let disableButton = false;
var lastSearchedCountries = [];
var SecondRoute = () => <View style={[{ height: height }]} />;
class PathexploredTab extends React.Component {
constructor(props) {
super(props);
this.imageMap = ['', Images.studyImage, Images.workImage, Images.residencyImage, Images.tourismImage];
this.state = {
isloading: false,
buttonone: false,
immibut1: false,
immibut2: false,
immibut3: false,
immibut4: false,
userInfoPopUpVisible: false,
countrybut1: false,
countrybut2: false,
countrybut3: false,
countrybut4: false,
filedsToShow: [],
countrybut5: false,
countrybut6: false,
selectedval: "Select the Country",
index: 0,
routes: [
{ key: "first", title: "Select Goals" },
{ key: "second", title: "Select Countries" }
],
checkconnection: false,
errorMessage: "",
isItemSelected: true,
currentlySelectedItemIndex: -1,
isItemChecked: true,
checkboxData: ""
};
}
componentDidUpdate = (nextProps) => {
Reactotron.log('=====', nextProps.userPressedGo)
}
componentWillReceiveProps = (nextProps) => {
}
componentWillMount = async() => {
const {
getUser: { userDetails },
authData: { token }
} = this.props;
this.props.dispatch(getUserDetails(userDetails.userid, token))
}
componentDidMount() {
setTimeout(() => {
this.props.start();
}, 1000);
immigrationInterst = [];
countryIntrest = [];
countryIntrestNow = [];
const {
getUser: { userDetails }
} = this.props;
}
callProceed = () => {
const {
isItemSelected,
currentlySelectedItemIndex,
isItemChecked
} = this.state;
if (isItemSelected) {
Alert.alert("Immigreat", "Please select any goal");
return;
}
const lastGoal = this.props.immigationInterest[0]
//This is a bit of a hacky fix but it works.
let allPrevCountriesFound = lastSearchedCountries.every(ai => countryIntrestNow.includes(ai))
&& (lastSearchedCountries.length == countryIntrestNow.length);
//We want to clear and search when:
//a) There is no exploration id
//b) Even if there is an exploration id but the lastGoal or last countries dont match
//Note: We make one exception for if exploration id exists but the lastSearchedCountries is just an empty list
let noExplorationId = (this.props.explorationId === "");
let countryGoalDontMatch = (lastGoal != currentlySelectedItemIndex || !allPrevCountriesFound);
let isProceedException = (lastSearchedCountries.length == 0 && !noExplorationId);
noExplorationId || (!noExplorationId && countryGoalDontMatch && !isProceedException)
?
this.clearAndSearch()
: Alert.alert(
"Immigreat",
"Previous exploration found. Would you like to continue?",
[
{
text: "START FROM BEGINNING",
onPress: () => {
this.props.dispatch(continueFromPrevious(0));
this.props.dispatch(backToInitialState());
this.props.dispatch(isKeepData(false));
this._searchData();
},
style: "cancel"
},
{
text: "CONTINUE",
onPress: () => {
lastSearchedCountries = [...countryIntrest];
this.props.dispatch(isKeepData(true));
this.props.didTapOnSearch();
}
},
{
text: "Cancel",
onPress: () => console.log("Canceled"),
style: "cancel"
}
],
{ cancelable: false }
);
}
_onPressBackButton = () => {
this.setState(
{
isItemSelected: true,
currentlySelectedItemIndex: -1,
isItemChecked: false
},
() => {
setTimeout(() => {
this.intialLoadValues();
//this.setState({ isItemSelected: true });
}, 0);
}
);
}
extraOptionsRefresh() {
const { currentlySelectedItemIndex, isItemChecked } = this.state;
this.setState({ isItemChecked: !isItemChecked })
switch (currentlySelectedItemIndex) {
case 1:
this.setState({checkBoxData:
"Do you want to explore options you may have after your studies?"});
break;
case 2:
this.setState({checkBoxData:
"Do you want to explore other goal options (such as studies) that can lead to work options?"});
break;
case 3:
this.setState({checkBoxData:
"Do you want to explore other goal options (such as studies or work) that could lead to permanent residency in the future?"});
break;
case -1:
this.setState({checkBoxData: ""});
break;
}
}
intialLoadValues() {
const { currentlySelectedItemIndex, isItemChecked } = this.state;
/*var checkBoxData = "";
switch (currentlySelectedItemIndex) {
case 1:
checkBoxData =
"Do you want to explore options you may have after your studies?";
break;
case 2:
checkBoxData = "Do you want to explore other goal options (such as studies) that can lead to work options?";
break;
case 3:
checkBoxData =
"Do you want to explore other goal options (such as studies or work) that could lead to permanent residency in the future?";
break;
case 4:
checkBoxData = "";
break;
}*/
FirstRoute = () => (
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<Animatable.View animation="fadeIn" duration={1200} style={{ flex: 1 }}>
<View
style={{
backgroundColor: "#DBDDDF",
alignItems: "center",
justifyContent: "center",
flex: 1
}}
>
<View style={{ padding: 20 }}>
<Text
style={{
textAlign: "center",
fontFamily: "SourceSansPro-Semibold",
color: "#2C393F",
fontSize: RFValue(12)
}}
>
Select the Immigration goal that you would be interested in
exploring
</Text>
<Text
style={{
textAlign: "center",
color: "#008BC7",
fontFamily: "SourceSansPro-Regular",
fontSize: RFValue(10)
}}
>
You can select/deselect ONLY one goal at a time by clicking the buttons. This is so we can help you hone your search!
</Text>
</View>
</View>
{(this.state.isItemSelected && this.state.currentlySelectedItemIndex < 0) ? (
<View style={{ marginTop: 30 }}>
{/*<Animatable.View animation="fadeIn" duration={1200} style={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}>*/}
<View style={styles.custombuttonView}>
<View style={{ width: "50%" }}>
<CopilotStep text="Select Your goals" order={1} name="study">
<WalkthroughableTouch
testID={`${Config.immigerat[0].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[0].code)
}
style={
this.state.immibut1
? styles.selectedbutton
: styles.buttonstyleview
}
>
<WalkthroughableText
style={
this.state.immibut1
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[0].value}
</WalkthroughableText>
</WalkthroughableTouch>
</CopilotStep>
</View>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[1].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[1].code)
}
style={
this.state.immibut2
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut2
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[1].value}
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.custombuttonView}>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[2].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[2].code)
}
style={
this.state.immibut3
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut3
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[2].value}
</Text>
</TouchableOpacity>
</View>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[3].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[3].code)
}
style={
this.state.immibut4
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut4
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[3].value}
</Text>
</TouchableOpacity>
</View>
</View>
{/*</Animatable.View>*/}
</View>
) : (
<View style={{ flex: 0.75, marginTop: 30 }}>
{/*<Animatable.View animation="fadeIn" duration={1200}>*/}
<View style={{ flexDirection: 'row', alignContent: 'center' }}>
<TouchableOpacity testID='goBackButton'
onPress={this._onPressBackButton} style={{ padding: 10 }} >
<View style={{ width: 80 }}>
<Icon name="chevron-left" size={30} color="black" />
</View>
</TouchableOpacity>
{<TouchableOpacity
onPress={() => this._immigreateIntrest("null")}
style={[styles.selectedbutton, { width: "50%" }]}
>
<Text style={styles.selectedbuttontext}>
{Config.immigerat[this.state.currentlySelectedItemIndex - 1].value}
</Text>
</TouchableOpacity>}
</View>
{currentlySelectedItemIndex !== 4 && (
<View
style={{
borderWidth: 1,
borderRadius: 3,
borderColor: "rgba(110,110,110,0.4)",
flex: 1,
marginHorizontal: 10,
marginTop: 30,
flexDirection: "row"
}}
>
<TouchableOpacity
activeOpacity={0.8}
onPress={() => {
this.extraOptionsRefresh()
//setTimeout(() => {
//this.extraOptionsRefresh();
//this.intialLoadValues();
//this.setState({ isItemChecked: !isItemChecked });
//}, 100);
}
}
style={{
// flex: 0.35,
alignItems: "center",
justifyContent: "center",
marginLeft: 15
}}
hitSlop={{ top: 20, bottom: 20, left: 50, right: 50 }}
>
<View
style={[
styles.button,
{
backgroundColor: "white",
borderColor: "rgba(110,110,110,0.4)",
borderWidth: 1,
borderRadius: 2,
width: 20,
height: 20
}
]}
>
{this.state.isItemChecked ? (
<Icon name={"check"} color={colors.LIGHT_BLUE} size={15} />
) : null}
</View>
</TouchableOpacity>
<Text
style={{
flex: 1,
marginVertical: 10,
marginLeft: 10,
fontFamily: "SourceSansPro-Bold",
color: "#242424",
fontSize: RFValue(12)
}}
>
{this.state.checkBoxData}
</Text>
</View>
)}
{(!this.state.isItemSelected && this.state.currentlySelectedItemIndex > 0) &&
<Animatable.View animation="fadeIn" duration={1200} style={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}>
<ResponsiveImage source={this.imageMap[this.state.currentlySelectedItemIndex]} initWidth="270" initHeight="220" />
</Animatable.View>
}
</View>
)}
<View>
<TouchableOpacity
testID='searchButton'
onPress={() => !disableButton && this.showAlert1()}
style={{
width: 130,
justifyContent: "center",
backgroundColor: colors.LIGHT_BLUE,
borderRadius: 100,
padding: 10,
alignSelf: "center",
marginTop: height > 700 ? 60 : 40,
marginBottom: 20
}}
>
<Text
style={{
textAlign: "center",
color: "#fff",
fontFamily: "SourceSansPro-Regular"
}}
>
Search
</Text>
</TouchableOpacity>
</View>
</Animatable.View>
</ScrollView>
);
SecondRoute = () => (
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<View style={{ backgroundColor: "white" }}>
<View
style={{
alignSelf: "center",
justifyContent: "center",
width: width
}}
>
<View style={{ margin: 20, alignSelf: "center" }}>
<Text
style={{
textAlign: "center",
fontFamily: "SourceSansPro-Semibold",
color: "#2C393F",
fontSize: 15
}}
>
Select all countries you are keen to explore
</Text>
<Text
style={{
textAlign: "center",
color: "rgba(44, 57, 63,0.6)",
marginTop: 20,
fontFamily: "SourceSansPro-Semibold"
}}
>
From:
</Text>
<View style={styles.loginView}>
<Field
name="selectcountry"
placeholder={this.state.selectedval}
component={this.renderDropdown}
data={Config.countries}
/>
</View>
<Text
style={{
textAlign: "center",
color: "rgba(44, 57, 63,0.6)",
marginTop: 20,
fontFamily: "SourceSansPro-Semibold"
}}
>
To:
</Text>
</View>
</View>
<View>
<View style={styles.custombuttonView}>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[0].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[0].code)
}
>
<Image
style={styles.countryIcon}
source={this.state.countrybut1
? Images.usa_selected
: Images.usa_unavailable}
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[1].value + 'interestButton'}`}
>
<Image
style={styles.countryIcon}
source={this.state.countrybut2
? Images.canada_selected
: Images.canada_unavailable}
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[2].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[2].code)
}
>
<Image
</TouchableOpacity>
</View>
</View>
<View style={styles.custombuttonView}>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[3].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[3].code)
}
>
<Image
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[4].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[4].code)
}
>
<Image
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[5].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[5].code)
}
>
<Image
/>
</TouchableOpacity>
</View>
</View>
</View>
<View>
<TouchableOpacity
testID='countrySearchButton'
onPress={() => !disableButton && this.showAlert1()}
style={{
}}
>
<Text
>
Search
</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
}
_countryIntrest(code) {
// alert(code);
var index = countryIntrest.indexOf(code);
var butstr = "countrybut" + code;
if (index == -1) {
countryIntrest.push(code);
countryIntrestNow.push(code);
this.setState({ [butstr]: true });
this.intialLoadValues();
} else {
countryIntrest.splice(index, 1);
countryIntrestNow.splice(index, 1);
this.setState({ [butstr]: false });
this.intialLoadValues();
}
}
_immigreateIntrest = async(code) => {
if(code === 4){
)
return;
}
const { isItemSelected } = this.state;
if (code === "null") {
);
} else {
await this.setState(
);
}
}
renderScene = ({ route }) => {
switch (route.key) {
case 'first':
case 'second':
default:
return null;
}
};
render() {
return (
<View style={{ flex: 1 }}>
{this.props.isLoading && (
<View
style={{
}}
>
<Loader />
</View>
)}
<TabView
removeClippedSubviews={Platform.OS === "android" ? true : false}
style={{
backgroundColor: this.state.index === 0 ? "#DBDDDF" : "white"
}}
navigationState={this.state}
removeClippedSubviews={Platform.OS === "android" ? true : false}
renderTabBar={props => (
<TabBar
}}
pass
getLabelText={({ route }) => route.title}
/>
)}
/>
<UserinfoPopUp
visible={this.state.userInfoPopUpVisible}
onClose={()=>this.setState({ userInfoPopUpVisible: false })}
userPopUpSubmit={this._userPopUpSubmit.bind(this)}
/>
</View>
);
}
}
mapStateToProps = state => ({
userPressedGo: state.pathReducer.getImmipathDetails.userPressedGo,
});
mapDispatchToProps = dispatch => ({
dispatch
});
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
reduxForm({
form: "pathexplorertab"
// validate
})
)(copilot({
tooltipComponent: TooltipComponent,
stepNumberComponent: StepNumberComponent
})(PathexploredTab));
Pathexplorer.js contains Pathexplorer class in which there is an component called ToolTipComponent from which i am calling an action but the action isn't reflected in mapStateToProps. The reason i am forced to do this is that i am using a library called react-native-copilot in which i have a custom tooltip component from which i want to access the state
Problem in this event:
onPress={store.dispatch(action)}
should be:
onPress={()=>store.dispatch(action)}
By the way you can connect your functional component like class component:
export default connect(
mapStateToProps,
mapDispatchToProps
)
)(TooltipComponent)
I didn't find any soulotion to do animated with FlatList,
I want to hide my Header when I scroll down like In Facebook app.
I tried To use FlatList with diffClamp() without success,
I don't know if I can do it with FlatList but I need also LazyLoading,
Someone Can help me?
This is my Header:
import React, { useState } from "react";
import {
View,
Animated,
Text,
Dimensions,
TouchableOpacity
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Ionicons } from "#expo/vector-icons";
const Header = props => {
const params = props.scene.route.params;
const [headerHeight] = useState(
params !== undefined && params.changingHeight !== undefined
? params.changingHeight
: Dimensions.get("window").height * 0.065
);
return (
<SafeAreaView style={{ backgroundColor: "rgb(152,53,349)" }}>
<Animated.View
style={{
width: Dimensions.get("window").width,
height: headerHeight,
flexDirection: "row",
backgroundColor: "rgb(152,53,349)"
}}
>
<TouchableOpacity
onPress={() => {
props.navigation.openDrawer();
}}
>
<View
style={{
paddingVertical: "15%",
justifyContent: "center",
paddingHorizontal: 25
}}
>
<Ionicons name="ios-menu" size={30} color={"white"} />
</View>
</TouchableOpacity>
<View style={{ justifyContent: "center", marginLeft: "23%" }}>
<Text
style={{
fontSize: 20,
fontWeight: "bold",
textAlign: "center",
color: "white"
}}
>
MyGameenter code here{" "}
</Text>
</View>
</Animated.View>
</SafeAreaView>
);
};
export default Header;
This is my FlatLIst:
import React from "react";
import { View, FlatList, StyleSheet } from "react-native";
import { EVENTS } from "../data/dummy-data";
import Event from "./Event";
const renderGridItem = itemData => {
return <Event item={itemData.item} />;
};
const ShowEvents = props => {
return (
<View style={styles.list}>
<FlatList
keyExtractor={(item, index) => item.id}
data={EVENTS}
renderItem={renderGridItem}
numColumns={1}
/>
</View>
);
};
const styles = StyleSheet.create({
list: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});
export default ShowEvents;
Use
onScroll={(e) => console.log(e.nativeEvent.contentOffset.y)}
Working Example: https://snack.expo.io/#msbot01/privileged-candies
import React, { Component } from 'react';
import { Text, View, StyleSheet, ScrollView, FlatList } from 'react-native';
import Constants from 'expo-constants';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
DATA: [],
previous: 0,
hide: false,
};
}
componentDidMount() {
var array = [];
for (var i = 0; i < 100; i++) {
var a = { id: i, value: i };
array.push(a);
}
this.setData(array);
}
setData(a) {
this.setState({
DATA: a,
});
}
Item({ title }) {
return (
<View
style={{
width: '100%',
height: 30,
marginTop: 5,
backgroundColor: 'green',
justifyContent: 'center',
alignItems: 'center',
}}>
<Text />
</View>
);
}
_onScroll(event) {
// console.log('>>>>>>>>>>>'+this.state.data);
if (this.state.previous < event) {
this.setState({
hide: true,
previous: event,
});
} else {
this.setState({
hide: false,
previous: event,
});
}
console.log(event);
}
render() {
return (
<View style={{ flex: 1 }}>
{this.state.hide == true ? null : (
<View
style={{
width: '100%',
height: 50,
justifyContent: 'center',
alignItems: 'center',
}}>
<Text>Hide me while scrolling</Text>
</View>
)}
<FlatList
onScroll={e => this._onScroll(e.nativeEvent.contentOffset.y)}
data={this.state.DATA}
renderItem={({ item }) => (
<View
style={{
width: '100%',
height: 30,
marginTop: 5,
backgroundColor: 'green',
justifyContent: 'center',
alignItems: 'center',
}}>
<Text />
</View>
)}
keyExtractor={item => item.id}
/>
</View>
);
}
}
const styles = StyleSheet.create({});
import React, { useState } from "react";
import { View, FlatList, StyleSheet, Platform, Dimensions } from "react-native";
import { EVENTS } from "../data/dummy-data";
import Event from "./Event";
const HeaderHeight = () => {
if (Platform.OS === "android" && Dimensions.get("window").height < 600)
return Dimensions.get("window").height * 0.075 + 20;
else if (Platform.OS === "android")
return Dimensions.get("window").height * 0.058 + 20;
else return Dimensions.get("window").height * 0.01 + 20;
};
const renderGridItem = itemData => {
return <Event item={itemData.item} />;
};
const ShowEvents = props => {
const [previous, SetPrevious] = useState(false);
const [hide, SetHide] = useState(false);
_onScroll = event => {
const headerHeight = HeaderHeight();
if (event > headerHeight) {
SetHide(true);
props.navigation.setParams({
hide: true
});
SetPrevious(event);
} else if (event < 0.1) {
SetHide(false);
props.navigation.setParams({
hide: false
});
SetPrevious(event);
}
};
return (
<View style={styles.list}>
<FlatList
onScroll={e => _onScroll(e.nativeEvent.contentOffset.y)}
keyExtractor={(item, index) => item.id}
data={EVENTS}
renderItem={renderGridItem}
numColumns={1}
/>
</View>
);
};
const styles = StyleSheet.create({
list: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});
export default ShowEvents;