I have been trying to navigate to the same screen with different parameters on react-native application. It is a category screen, where I don't want the user to go back and select different categories to view products. I have made a screen where products from categories are displayed.
Below is my code:
<View style={styles.horizontalSlider}>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={this.state.DataSource}
keyExtractor={(item, index) => index.toString()}
extraData={this.state.selectedItem}
renderItem= { ({item}) => (
<TouchableOpacity onPress={(category) => navigate.push('CategoryScreen', {item})}>
<ImageBackground style={styles.profileImgContainer} >
<Image source={{ uri: item.images }} style={[styles.profileImg, , { borderColor: 'green', borderWidth:2 }]} />
</ImageBackground>
</TouchableOpacity>
)}
/>
</View>
If you want to navigate to the same screen with different parameters and be unable to go back, use this.props.navigation.replace('CategoryScreen', { ...new params here... })
If you want to change current navigation params without navigating, use this.props.navigation.setParams()
(navigation prop)
But your problem is not a navigation problem. You don't need multiple screens for that. Solve it with react. All you need to do is to render your list conditionally depending on what category (or circle item?) is currently selected. Store this information in state and use it in render
You can add unique key:
this.props.navigation.navigate({ routeName: route, params: params, key: route + params.id })
Related
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.
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");
}
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>;
I am having an issue (this is probably something I am ignoring within the render cycle) maintaining the position of two different scroll views when some of its child components are updated.
I have a hierarchy of views that is like:
<ScrollView vertical scrolling ability>
...
<ScrollView horizontal and vertical scrolling ability>
...
<Matrix>
<Cell updateCellStatusHandler={handler}>
</Matrix>
...
</ScrollView>
</ScrollView>
So, the updates on the internal cells, are resetting both scrolls on cell status update and this generates a super weird experience with the user having to scroll down/left/right back to continue interacting with the Matrix of cells with a status I have.
I have tried to save the scrollOffset (x,y) using useState but if I change some cell, the state is reseted to (0,0) which is my initial state.
const [scrollOffset, setScrollOffset] = useState({
scrollX: 0,
scrollY: 0,
})
But without luck.
<ScrollView
{...props}
scrollEventThrottle={16}
ref={scrollReference}
// tslint:disable-next-line: jsx-no-lambda
onScroll={event => {
setScrollOffset({
scrollX: event.nativeEvent.contentOffset.x,
scrollY: event.nativeEvent.contentOffset.y,
})
}}
onScrollEndDrag={event => {
console.log(event.nativeEvent.contentOffset.y)
console.log(event.nativeEvent.contentOffset.x)
}}
>
{props.children}
</ScrollView>
One possible approach to solve this is to have a mechanism that allow me to save the scroll position before the update. But this will complicate a lot the communication between components, etc.
By the way, the cell status update is being handled via Redux.
If some of you can bring you some light over this, would be great.
---- UPDATE 1 (Code of the panel component added) ----
Parent component is:
<View style={styles.container}>
<CustomScrollView enableResetScrollToCoords={false}>
<Section>
<WhiteContainer>
<View style={styles.rateContainer}>
<DescriptionTextStatus
statusText={getMessageForRate(availabilityRate)}
descriptionText={getDescriptionForRate(
availabilityRate,
isTeacher,
)}
icon={getImageForRate(availabilityRate)}
/>
</View>
</WhiteContainer>
</Section>
{!loggedUserIsTeacher() && <AvailabilityStart />}
<AvailabilityPanel />
<AvailabilityStatus />
<AvailabilityButtonSave />
</CustomScrollView>
</View>
Availability Panel is one of the childs
export const AvailabilityPanel: React.FunctionComponent<{}> = () => {
const panel: Cell[][] = useSelector((state: ReduxStore) => {
return get(state.entities, 'availability.panel', undefined)
})
if (panel === undefined) {
return <Nothing />
}
return (
<Section>
<WhiteContainer>
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
colors={[Palette.White, Palette.White68]}
>
<View style={styles.rateContainer}>
<DescriptionTextStatus
statusText={strings.warning}
descriptionText={strings.selectionMessage}
icon={'clock'}
/>
<View style={styles.separator} />
</View>
<View style={styles.container}>
<ScrollView
style={styles.scrollView}
directionalLockEnabled={false}
horizontal={true}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
>
<View style={styles.contentContainer}>
<View style={styles.weekdaysContainer}>
<PanelHeader weekdays={weekdays} />
</View>
<View style={styles.rowsContainer}>
{hours.map((hourLabel: string, index: number) => {
return (
<PanelRow
key={index}
hourLabel={hourLabel}
hoursRow={panel[index]}
rowIndex={index}
/>
)
})}
</View>
</View>
</ScrollView>
</View>
</LinearGradient>
</WhiteContainer>
</Section>
)
}
Thanks in advance.
ScrollView does not reset scroll position because of child updates, regardless of whether you use Redux or not. You don't need to try to patch it with workarounds like saving current scroll positions. Rather just figure out what's wrong with your setup
It's hard to tell because you didn't provide your actual code, but I'm pretty sure one or both ScrollViews are remounted on updates (old ScrollView is removed and new one is created in its place with its own scroll position). It's likely that you are declaring new components inside render function so React will just remount them every time
I think the overall idea of saving the scroll position of your scrollview is good.
I think the fact that your state is reset to 0 is probably due to Redux (not sure however, could you precise how your component is connected to redux ?). I am not so familiar with Hooks, but in a React Class component, I would try to save the scroll position in a non state property of the class. Maybe save it in a variable outside of your functional component ?
Then in the handler to manage cell updates, you could ensure that your scrollview scrolls to the position you saved (using ScrollView.scrollTo(), with {animated: false} option so that the animation is not visible for the user)
i have a flatlist and 5 items I want every item to navigate different pages
but currently it gives me an error
<FlatList style={{backgroundColor:'#ffffff'}}
data={[{key: 'Book',details:'sssss',icon:'ios-calendar-outline',way:'Home'}]}
renderItem={({item}) => <TouchableOpacity onPress={() => navigate({item.way})}>
how can I pass {item.way} variable into navigate()
You have a syntax error here navigate({item.way}). Try:
navigate(item.way)