React Native - passing data model from Flat list - reactjs

I have a FlatList:
<ScrollView nestedScrollEnabled={true}>
<Screen style={styles.screen}>
<TouchableOpacity onPress={() => navigation.navigate("ProfileDetailScreen")}>
<FlatList
data={users}
renderItem={renderItem}
keyExtractor={item => item.uid}
/>
</TouchableOpacity>
</Screen>
</ScrollView>
And Im getting some data from firebase like:
useEffect(() => {
firebaseUsers
.onSnapshot(
querySnapshot => {
const newUsers = []
querySnapshot.forEach(doc => {
const user = doc.data()
user.id = doc.id
newUsers.push(user)
});
setUsers(newUsers)
},
error => {
console.log(error)
}
)
}, [])
The data I get from firebase has name, image and age (and more more fields).
How can I pass all the data for a single user into the ProfileDetailedScreen?
Not sure the correct way to achieve this (not sure If I need to create data models etc?)

I don't know firebase that well but I have experience in RN. From what I'm understanding, you're going to want to make the renderItem function in your FlatList a function that returns a TouchableOpacity with navigation to the ProfileDetailedScreen component while also passing the user object. You'll display the user details in the ProfileDetailedScreen.
Passing items in navigation documentation
/* 'item' is a user from the users array you passed into the data property of your FlatList above */
renderItem = ({item}) => (
<TouchableOpacity onPress={() => navigation.navigate("ProfileDetailScreen", item)}>
<Text> item?.name </Text> {/* show brief info about user */}
</TouchableOpacity>
)
If you're using Redux for your application state, you could also navigate only to "ProfileDetailScreen" and dispatch an action that sets a currentUser in state. Your "ProfileDetailsScreen" would then pull the currentUser from state. This way has more moving parts but the component piece would look something like this:
/* 'item' is a user from the users array you passed into the data property in your FlatList above */
renderItem = ({item}) => (
<TouchableOpacity onPress={this.setUserAndNavigate.bind(this, item)}>
<Text> item?.name </Text> {/* show brief info about user */}
</TouchableOpacity>
)
setUserAndNavigate = (user) => {
this.props.setUser(user);
navigation.navigate("ProfileDetailScreen");
}

Related

How to Limit render element Flat List and add more content in React Native

I want like that flatlist render only 5 checkbox items and then when I click to +5 more button it will show 5 more checkbox list.In this all checkbox list appearing but i want only five
Please help me how to achieve that
Thanks in advance
const renderResourceList = renderData => {
return (
<FlatList
data={renderData}
initialNumToRender={5}
maxToRenderPerBatch={5}
pagingEnabled={true}
nestedScrollEnabled={true}
renderItem={({item}) => (
<View style={styles.card}>
<TouchableOpacity
onPress={() => {
if(resourceTypeArray.includes(item)){
setResourceTypeArray(currentList => {
return currentList.filter(items => items !== item);
});
}
else{
setResourceTypeArray(currentList => [
...currentList,
item
]);
}
onSetResourceType(item);
}}
style={styles.modalBtn}>
<Icon
name={
resourceTypeArray.includes(item) ? 'checkbox-marked' : 'checkbox-blank-outline'
}
size={18}
color="#353C3C"
style={{bottom: -1}}
/>
<View style={styles.textWrapper}>
<Text style={styles.modalText}>{item.charAt(0)}
{item.toLowerCase().slice(1).replace(/_/g, ' ')}</Text>
</View>
</TouchableOpacity>
</View>
)}
/>
);
};
I tried but this not working
I used a package called flatlist-react to handle this for me. A decent tutorial for this can be found here.
With this package, you can directly specify and limit the items rendered with the limit prop. Here is an example:
<FlatList
limit="2,-2"
list={people}
renderItem={Person}
/>
If you keep track of the limit prop variables using state, you can dynamically change these values when you click 5+ more in order to render whatever part of your data you would like.

pass database data to another screen in react native

Now I wanted to implement a function that when I click on a list of data from mysql server on my react native app, it will move to another screen and pass the detail of the data into it here is the code that I have implement
const GetJobDetail=useCallback= (user,job, jobid, machinecode, startTime) =>{
navigation.navigate('Jobview', {
UserId : user,
Job : job,
JobId:jobid,
MachineCode : machinecode,
StartTime : startTime
},[]);
}
return (
<View style={{ flex: 1, padding: 24 }}>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Button title={item.job} style={styles.rowViewContainer} onPress={()=>navigation.navigate(GetJobDetail(item.user,item.job,item.jobid,item.machinecode,item.startTime))}/>
)}
/>
)}
</View>
);
I have already successful fetch the data into my react native apps, the data look like
the data is only show the job of the user instead of showing all detail if I enter userid='1111' then it will only show the job for userid='1111'. but now i wish to implement that if I clicked the job in this list it will move to next screen and send all the details to that screen using route.params. I have tried using callback function but it gave me error "useCallback" is read-only.
I also founded some source from other site but it is in class component the code will look like this.
i am sure that this first is the function that pass the value to another screen
GetStudentIDFunction=(student_id,student_name, student_class, student_phone_number, student_email)=>{
this.props.navigation.navigate('Third', {
ID : student_id,
NAME : student_name,
CLASS : student_class,
PHONE_NUMBER : student_phone_number,
EMAIL : student_email
});
}
and this one is calling the function and pass the data to another screen
renderRow={ (rowData) => <Text style={styles.rowViewContainer}
onPress={this.GetStudentIDFunction.bind(
this, rowData.student_id,
rowData.student_name,
rowData.student_class,
rowData.student_phone_number,
rowData.student_email
)} >
{rowData.student_name}
</Text> }
pls help me to point out what is my mistake or error. Thanks
update:
after tried multiple time finally it works with this code. On the first page it get the data
const GetDetail=(id,user,job,jobid,machinecode,startTime)=>{
navigation.navigate('JobView',{Id:id,UserId:user,Job:job,JobId:jobid,MachineCode:machinecode,StartTime:startTime});
}
return (
<View style={{ flex: 1, padding: 24,backgroundColor:'cyan' }}>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Text style={styles.rowViewContainer} onPress={()=>{GetDetail(item.id,item.user,item.job,item.jobid,item.machinecode,item.startTime)}}>{item.job}</Text>
)}
/>
)}
</View>
);
}
On this screen it pass the data from previous screen by using route.params&&route.params.variable\\variable=your own variable that carry the data from th eprevious screen
useEffect(()=>{
setCode(route.params && route.params.MachineCode)
setUserid(route.params && route.params.UserId)
setJob(route.params && route.params.Job)
setJid(route.params && route.params.JobId)
setStarttime(route.params && route.params.StartTime)
setId(route.params && route.params.Id)
},[]
)
Hope this will help you guys when faced the same problem :)
Store your data in some useState after fetching. You can send data to another screen/component in two ways:
You can pass data as props or use a callBack if those screens/components are in parent-child relationship.
Parent to child: Pass as props
<FlatList
data={customerData}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => index}
renderItem={({item, index}) => (
<KYC_ListCell
itemdata={customerData[index]}
onItemClick={() => {
props.updateCustomerInformation(customerData[index]);
navigation.navigate('Customer360Info');
}}
/>
Using a call back to pass data from child to parent
//Parent
<HeaderView
username={'HelpDesk'}
showHeaderWithSearch
placeholderText={'Customer ID'}
showRefreshIcon
onMenuClick={() => {
setModalVisible(true);
}}
onRefreshClicked={() => {
getComplaintsListOnPageLoad();
}}
onSearchClicked={text => {
setSearch(text);
getSearchedItem(text);
}}
/>
//child
<Search
value={search}
placeholderText={props.placeholderText}
onChangeText={text => setSearch(text)}
onClearText={() => setSearch('')}
onSearchPressed={() => props.onSearchClicked(search)}
/>
You can pass data while navigating as route param

FlatList, Props ListHeaderComponent and Dynamic flatlist data

Sorry for the title, I wasn't inspired, and I didn't know what title to put for my problem.
I'm using Socket.io on my React native application to render some dynamics datas.
I'm using FlatList to display all this datas, and I need to show some contents like filters and buttons at the top of the FlatList.
So In my FlatList Props, I used ListHeaderComponent and in this component I display one other flatlist and contents.
My problem is :
When the main FlatList is updated with one of the Socket.io response (Every 5sec), all the components displayed by ListHeaderComponent aren't usable for a bit of time.
This period is like 500ms or less, but in the ListHeaderComponent I have some buttons / filters, and they are not clickable during this period.
And the problem is repeated each time the FlatList data is updated.
You can see my code (simplyfied) here :
export default function MyList({ navigation }) {
const [myData, setMyData] = useState<ResponseType[]>([])
// Socket Io
const socket = io(SOCKET_URL, { forceNew: true, timeout: 5000 })
useEffect(() => {
socket.on("connect", () => {
console.log("Connected to Socket ID : ", socket.id)
})
return () => {
socket.disconnect()
socket.close()
}
},[])
socket.on("socketResponse", (data: ResponseType) => {
setMyData(prevDate => [...prevDate, data])
})
const renderFilterItem = ({ item }: { item: Filter }) => <Text key={ item.id }>{ item.title }</Text>
const renderListItem = ({ item }: { item: ResponseType }) => <Text key={ item.id }>{ item.id }</Text>
const ListTop = () => (
<>
<TouchableOpacity onPress={() => navigation.navigate('HomePage')}>
<Text>BACK CONTENT</Text>
</TouchableOpacity>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={someFilters}
keyExtractor={(item) => item.id}
renderItem={renderFilterItem}
/>
</>
)
return (
<FlatList
ListHeaderComponent={ListTop}
data={myData}
keyExtractor={(item) => item.id}
renderItem={renderListItem}
maxToRenderPerBatch={5}
windowSize={2}
/>
)
}
I don't know how to explain better my problem. But If I move the component of ListHeaderComponent above the FlatList, there is no more problem.
But If I do this, just the FlatList is scrollable, and I want all the page scrollable.
I can't wrap my Flatlist with a ScrollView because of this error : VirtualizedLists should never be nested inside plain ScrollViews with the same orientation
Has anyone faced this problem ?
Thanks
try to use optimization for ListTop component as a possible problem here would be rendering of your functional component due to change of parent one.
here is the code sample.
import React, {useCallback} from 'react';
// your other codes
const ListTop = useCallback(() => (
<>
<TouchableOpacity onPress={() => navigation.navigate('HomePage')}>
<Text>BACK CONTENT</Text>
</TouchableOpacity>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={someFilters}
keyExtractor={(item) => item.id}
renderItem={renderFilterItem}
/>
</>
), [someFilters]);
here the component will be memoized until there is no change in someFilters.

FlatList rendering is heavy for big data set

In my application I have a FlatList with dataset of 100 items in it. Each item has a complex UI and I noticed that it's taking a heavy toll on performance. The page that has the list takes up to 5 seconds to load.
I noticed that the moment the component is rendered for the first time, the renderItem function of the FlatList is also called for each and every item in my data set, I also noticed that it also happens if there any other setState change for other stuff on that page. Is there a way to prevent this re-rendering of the flat list or at least to re-render only the visible items - just like with Recycle with in native Android?
How can I only render the visible items when the component first appears?
I tried to use initialNumToRender and maxToRenderPerBatch but neither have worked.
Here is an example of the code:
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const [text, setText] = React.useState('')
const renderItem = ({ item }) => {
console.log("Render Item")
return (<Item title={item.title} />)
};
return (
<SafeAreaView style={styles.container}>
<TextInput
value={text}
onChangeText={(val) => setText(val)}
/>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
initialNumToRender={6}
maxToRenderPerBatch={6}
/>
</SafeAreaView>
);
}
If I try to type something in TextInput the whole list re-renders but nothing in the list has changed.. how can I prevent this?

InfiniteScroll using ScrollView - React Native

I have a list using the ScrollView of react native itself. Basically, I build a list dynamically through an API return.
async fetchData(userSearch) {
const {route} = this.props;
const {params} = route;
const {type} = params;
this.setState({
loading: true,
});
const responseProcedures = await scheduleResource.getProcedures(userSearch);
this.setState({
procedures: responseProcedures.data,
loading: false,
});
}
<ScrollView
onScroll={(event) => this.shouldLoadMoreContent(event)}
>
{procedures.map(procedure => (
<ArrowBox key={procedure.id} onPress={() => RootNavigation.navigate('ProcedureDetails', {procedure})}>
<Text bold style={styles.ProcedureTitle}>
{procedure.name}
</Text>
{!!procedure.synonyms.length && (
<>
<Text bold style={styles.ProcedureSynonymTitle}>
SinĂ´nimos
</Text>
<View style={styles.ProcedureSynonymOptionsContainer}>
{procedure.synonyms.map(synonym => <Text style={styles.ProcedureSynonymOption} key={synonym}>{synonym}</Text>)}
</View>
</>
)}
</ArrowBox>
))}
</ScrollView>
The problem is that I load the entire return from the API and it slows down.
I would like to know how to dynamically load the content and make new calls in the api, when I reach the end of the page.
Api allows me to place offset and limit.
Could someone give me some example?
Thanks!!!!!
Basically the ScrollView is not designed to handle dynamic data, the correct component that is designed to perform this function is called Flatlist. It works almost exactly like ScrollView but it is faster and will only render components that are shown on the screen.
Please import Flatlist from React Native like this...
//At the top of your file, please import FlatList together with all the modules that you want
import { FlatList, Text, View } from "react-native";
Then replace the entire ScrollView in your code with a Flatlist like this:
<FlatList
keyExtractor={(procedure) => procedure.id}
data={this.state.procedures}
renderItem={(procedure) => {
return (
<ArrowBox
key={procedure.id}
onPress={() =>
RootNavigation.navigate("ProcedureDetails", {
procedure })}>
<Text bold style={styles.ProcedureTitle}>
{procedure.name}
</Text>
{!!procedure.synonyms.length && (
<>
<Text bold style={styles.ProcedureSynonymTitle}>
SinĂ´nimos
</Text>
<View
style={styles.ProcedureSynonymOptionsContainer}>
{procedure.synonyms.map((synonym) => (
<Text
style={styles.ProcedureSynonymOption}
key={synonym}>
{synonym}
</Text>
))}
</View>
</>
)}
</ArrowBox>
);
}}
></FlatList>;

Resources