It is working fine with ScrollView but not working with Animated.ScrollView
"undefined is not a function"
<Animated.ScrollView scrollEventThrottle={1} ref="_scrollView">
{content}
</Animated.ScrollView>
<Button title='Button' onPress={() => { this.refs._scrollView.scrollTo(0); }}/>
Try this to get the actual ref of the Animated.ScrollView component:
this.refs._scrollView.getNode().scrollTo({x: 0, y: 0})
Update: Use getNode() instead of accessing _component directly as it should be treated as an internal field.
scrollTo() accepts and object as a parameter, where object contains: {x:<number>, y:<number>, animated:<boolean>}
You also have to make sure that refs are really set. That's probably the reason why you're getting undefined is not a function.
So, in order to scroll top, I'd do it like:
onPress={() => {
if (this.refs._scrollView) {
this.refs._scrollView.scrollTo({x:0, y:0});
}
}}
Related
I'm trying to call scrollToEnd() in a screen that uses https://github.com/APSL/react-native-keyboard-aware-scroll-view and I get the error:
"cannot read property 'props' of undefined".
My code looks like this:
let scroll
(at the beginning of the file)
Then, inside the return:
<KeyboardAwareScrollView innerRef={ref => { scroll = ref }}>
my scrollable code
</KeyboardAwareScrollView>
And then there is a button which has
onPress={() => scroll.props.scrolltoEnd()}
Clicking the button gives the error above, which makes me think I'm not using innerRef correctly? Do I need to use useRef instead at some point? Any help is appreciated, thanks!
on KeyboardAwareScrollView use React.useRef
const scrollRef = React.useRef(null);
<KeyboardAwareScrollView
ref={scrollRef}
....
And on your input, listen onContentSizeChange
<Input
onContentSizeChange={(e) => {
if (scrollRef && scrollRef.current) {
scrollRef.current?.scrollToEnd();
}
}}
/>
You must use innerRef instead of ref and it will work.
<KeyboardAwareScrollView
innerRef={(ref) => {
scrollRef.current = ref;
}}
When I use onEndReached function in FlatList, it gets called automatically.
Below is the link of this issue.
Link
Is there a solution available for it or any alternative in iOS?
Edited:
Below is the code I tried but this doesn't seems to work.
constructor(props){
super(props);
this.state = {
flatListReady:false
}
}
loadMore(){
if(!this.state.flatListReady){
return null;
}
else{
alert("End Reached")
}
}
_scrolled(){
this.setState({flatListReady:true});
}
render() {
return (
<Layout style={{ flex: 1 }}>
<FlatList
data={listData}
renderItem={({item}) => this._renderItem(item)}
keyExtractor={(item, index) => item.key}
onEndReached={() => this.loadMore()}
onEndReachedThreshold={0.5}
onScroll={() => this._scrolled()}
/>
</Layout>
Try this,
onEndReachedThreshold={0.5}
onEndReached={({ distanceFromEnd }) => {
if(distanceFromEnd >= 0) {
//Call pagination function
}
}}
Sometimes things don't work like they are supposed to, at the end of the day it's not native code where, so may the order of your components or the fact that the Flatlist is encapsulated in a component that is not intended to be, or there is some property should be passed to the Flatlist component itself to activate the onEndReached callback properly.
I've faced this myself, and I didn't know what to do to make it work properly.
A beautiful workaround is derived from the fact the Flatlist inherits ScorllView properties. so you could use the onScroll property to detect if the end has reached or not.
<FlatList
data={this.props.dashboard.toPreviewComplaints}
onScroll={({nativeEvent})=>{
//console.log(nativeEvent);
if(!this.scrollToEndNotified && this.isCloseToBottom(nativeEvent)){
this.scrollToEndNotified = true;
this.loadMoreData();
}
}}
/>
this.scrollToEndNotified is used as a flag not to abuse the call to the loadMore endpoint
isCloseToBottom({layoutMeasurement, contentOffset, contentSize}){
return layoutMeasurement.height + contentOffset.y >= contentSize.height - 100;
}
So whenever it succeed in the isCloseToBottom call it means that you have reached the end of the list, so you can call the loadMoreData function
handle this function very carefully,
endReached=()=>{
//take care of ES6 Fat arrow function and trigger your conditions properly with current state and new state data or current state with new Props.
Based on those conditions only, you need to trigger the other API call
}
<FlatList data={this.state.data}
extraData={this.state.load}
renderItem={this.renderCard}
keyExtractor={item => item.fundRequestId}
onEndReached={this.endReached}
onEndReachedThreshold={.7}
ListFooterComponent={this.renderFooter}
/>
I'm trying to update booleans with setState onPress. Depending on which button pressed, other booleans will be set to false or respectively true.
Code:
export default class SettingsScreen extends React.Component {
constructor(){
super();
this.state = {
isMeat: true,
isVegan: false,
isVegetarian: false,
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.menuTop}>
<MenuButton navigation = {this.props.navigation} />
<Text style={styles.menuText}>Settings</Text>
</View>
<View style = {styles.body}>
<Button title="make it vegan!"
style = {styles.vegan}
onPress = {()=> {
this.setState({isMeat : false}, {isVegan: true}, {isVegetarian: false})
}}
>
make it vegan!
</Button>
<Button title="vegetarian please"
style = {styles.vegetarian}
onPress = {()=> {
this.setState({isMeat : false}, {isVegan: false}, {isVegetarian: true})
}}
>
vegetarian please
</Button>
<Button title="meat me up, Scotty!"
style = {styles.meat}
onPress = {()=> {
this.setState({isMeat : true}, {isVegan: false}, {isVegetarian: false})
}}
>
meat me up, Scotty!
</Button>
</View>
</View>
);
}
}
When I press one of the buttons I get the error message: Invariant Violation: Invalid argument passed as callback. Expected a function. Instead received: [object Object] but I don't understand why.
Ok, let's dig into this. The other answers are correct in showing how to fix your code but don't explain why they are correct. You said it happens when you hit the button, so it's related to onPress.
onPress = {()=> {
this.setState({isMeat : false}, {isVegan: true}, {isVegetarian: false})
}}
This is what you have in the button, specifically, setState(...) passed inside of a thunk / arrow function. The thunk/arrow function is good—it matches the type required by onPress which is a function and runs setState when you press the button. So far, so good.
Now, let's take a look at setState's docs in React, specifically what arguments it takes. If you look below, it takes two arguments—an updater (the classical setState object) and a callback.
setState(updater[, callback])
Ok, let's look at what you have again, even more closely:
this.setState({isMeat : false}, {isVegan: true}, {isVegetarian: false})
So, if we compare what you wrote with what is in the docs, you've passed {isMeat: false} as the updater, {isVegan: true} as the optional callback, and {isVegetarian: false} as a third, completely unused argument.
{isMeat: false} is NOT a function, hence you're getting the message you see. THAT's why you're seeing the invariant violation.
You can use setState to assign multiple properties at once, and avoid multiple calls like a previous answer suggested, like this:
this.setState({
isMeat: false,
isVegan: true,
isVegetarian: false
})
Maybe because you're passing multiple objects into your setState() functions?
Try switching them out for single objects updating only the properties you want to change. For example:
<Button title="make it vegan!"
style = {styles.vegan}
onPress = {()=> {
this.setState({isVegan: true})
}}
>
Like this it works:
<Button title="make it vegan!"
style = {styles.vegan}
onPress = {()=> {
this.setState({isMeat : false})
this.setState({isVegetarian : false})
this.setState({isVegan : true})
}}
>
make it vegan!
</Button>
I had the error because I was not passing a callback to OneSignal.promptForPushNotificationsWithUserResponse
found it while reading the stacktrace
So that's what my render list looks like:
renderEvent(){
return this.props.eventList.map(listedEvent=>
<CardSection key={listedEvent._id}>
<EventListItem>
{listedEvent.eventName}
</EventListItem>
<DeleteButton
onClick={this.deleteEvent(listedEvent._id)}
key={listedEvent._id}
/>
</CardSection>
);
}
and here the rendering of the whole list
render(){
if (this.props.eventList !== undefined) {
return(
<Card>
{this.renderEvent()}
</Card>
)
}else{
return(
<View>
<Spinner/>
</View>
)
}
}
}
So far so good, the list and the delete button appear correctly, yet when I try to delete one line, it addresses all. I created my event handler which for now, only logs the passed id.
deleteEvent(eventID){
console.log(eventID)
}
Yet when called, it logs all the _ids on the list. What am I doing wrong? How can I make sure I'm passing one single id of the list item I'm clicking on?
Thank you!
Problem is that you are rather than passing a deleteEvent function to onClick prop you are executing it. This causes to deleteEvent fire for each item while rendering.
You can sort this out by changing this,
onPress={this.deleteEvent(listedEvent._id)}
to this
onPress={() => this.deleteEvent(listedEvent._id)}
This will also assure that deleteEvent is bind with this.
I built my navigation based on Ex-navigation's example
Everything is working as expected, but I don't know how to Sign out
I have a <Main/> component which renders a <DrawerNavigationMenu/> as in the example
.This is my <DrawerNavigationMenu/>
render() {
return (
<DrawerNavigation
renderHeader={this._renderHeader}
drawerWidth={300}
initialItem="home">
<DrawerNavigationItem
id="home"
selectedStyle={styles.selectedItemStyle}
renderTitle={isSelected => this._renderTitle('Home', isSelected)}
renderIcon={isSelected => this._renderIcon('md-home', isSelected)}>
<StackNavigation
id="home"
defaultRouteConfig={{
navigationBar: {
backgroundColor: '#2497b7',
tintColor: '#fff',
height: 60,
},
}}
initialRoute={Router.getRoute('home')}/>
</DrawerNavigationItem>
<DrawerNavigationItem
id="logout"
selectedStyle={styles.selectedItemStyle}
renderTitle={isSelected => this._renderTitle('Logout', isSelected)}
renderIcon={isSelected => this._renderIcon('md-exit', isSelected)}>
<StackNavigation
id="root"
initialRoute={Router.getRoute('root')}/>
</DrawerNavigationItem>
</DrawerNavigation>
);
}
In the "logout" item I need to reset the navigation stack and render my Root scene without the chance of going back
I tried using initialStack= instead of initialRoute=, like this
<StackNavigation
id="root"
initialStack={[Router.getRoute('root')]}/>
But when I hit (Android)back, it still going back to Home scene. I'm not using Redux explicitly here. Is this the right way to implement a sign out navigation? Any ideas? Please!
Give DrawernavigationItem props onPress and call a function that switches between Authentication and Landing pages.
<DrawerNavigationItem
id="Sign out"
selectedStyle={styles.selectedItemStyle}
onPress={()=>{this.signOut()}}
renderTitle={isSelected => this._renderTitle('Sign out', isSelected)}
/>