KeyboardAwareScrollView props innerRef scrollToEnd not working - react-native

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;
}}

Related

react-native-snap-carousel is very laggy for large data

I am using react-native-snap-carousel to swipe through images. When there is like 0-10 images it's working fine, but otherwise it's very laggy. I tried the optimization methods but didn't fix it.
Here is my implementation (selectedItems is the data I have):
const renderItem = useCallback(
({ item, index }) => {
return (
<CarouselImage
ad={ad}
item={item}
index={index}
showImage={showImage}
/>
);
},
[ad, showImage]);
return ad?.videos?.length > 0 || ad?.images?.length > 0 ? (
<View style={styles.container}>
<Carousel
initialNumToRender={selectedItems.length}
maxToRenderPerBatch={5}
ref={carouselRef}
swipeThreshold={5}
itemWidth={wp(375)}
data={selectedItems}
sliderWidth={wp(375)}
enableMomentum={false}
lockScrollWhileSnapping
renderItem={renderItem}
onSnapToItem={(index) => setActiveSlide(index)}
/>
<Pagination
activeOpacity={1}
tappableDots={true}
animatedDuration={100}
inactiveDotScale={0.4}
inactiveDotOpacity={0.4}
carouselRef={carouselRef}
dotStyle={styles.dotStyle}
activeDotIndex={activeSlide}
dotsLength={selectedItems.length}
containerStyle={styles.pagination}
dotContainerStyle={styles.dotContainer}
inactiveDotStyle={styles.inactiveDotStyle}
/>
</View>
Is there something I am missing. Also, is there an alternative library that runs better with large data ?
Try this alternative library: react-native-banner-carousel-updated
I'm using this with more than 20 images and it's works fine.
I'm assuming that the optimization you've tried is what is described in the react-native-snap-carousel library docs...
I too found that every swipe was causing my screen's component to re-render.
You might be thinking...
I think it has to do with the state I am updating each time I scroll the component is re-rendered. Do you have ant idea how to solve this ?
To prevent the re-rendering of your <Carousel ... /> component, the optimization that you want to look at is to utilize React.memo()
Try refactoring your <Carousel ... /> component to a new component file, something like this...
Gallery.js
import React from "react";
import CarouselCardItem, { SLIDER_WIDTH } from "./CarouselCardItem";
import { ALL_RECIPES } from "../config/Recipe/allRecipes";
import Carousel from "react-native-snap-carousel";
const Gallery = ({ carouselRef, selectedItems, setActiveSlide}) => {
console.log("render"); // <== This will render only when props change (ie. the ref - which should not change, or you pass fresh data - in which case you want it to re-render)
return (
<Carousel
initialNumToRender={selectedItems.length}
maxToRenderPerBatch={5}
ref={carouselRef}
swipeThreshold={5}
itemWidth={wp(375)}
data={selectedItems} // <== selectedItems could be passed in as prop, or from app state
sliderWidth={wp(375)}
enableMomentum={false}
lockScrollWhileSnapping
renderItem={renderItem}
onSnapToItem={(index) => setActiveSlide(index)}
/>
);
};
const GalleryMemo = React.memo(Gallery);
export default GalleryMemo;
Then in your screen file, use it
<GalleryMemo carouselRef={carouselRef} selectedItems={selectedItems} setActiveSlide={setActiveSlide}/>

React native useRef is giving me undefined

I am trying to use useRef hook this way.
I want to get the value of textInput with it
let tagsRef = useRef('');
<TextInput
ref={tagsRef}
style={styles.textInputStyle}
placeholder={'Add tags to subscribe to them'}
placeholderTextColor={'lightgray'}
/>
</View>
I am using react-native version:0.63.3
When I
console.log(----tag', tagsRef.current.focus());
It gives me undefined
Any suggestions please?
Check this its Officially RN Documentation
https://reactjs.org/docs/hooks-reference.html#useref
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
It is depending on where do you use the ref. The ref is only filled after the first rendering. You can use it for instance in an event handler on the element.
Another point: You might see that the focus method does not return anything. So when you see an undefined in your console, it is properly related to that problem.
But without further context of your code and your problem, it is hard to give a more detailed answer.

How to solve blink image in react-native-snap-carousel?

How to solve blink image when back to first item in react-native-snap-carousel ? I try to look for many examples but fail all.
This is my script :
renderSlider ({item, index}) {
return (
<View style={styles.slide}>
<Image source={{uri: item.cover}} style={styles.imageSlider} />
</View>
);
}
<Carousel
ref={(c) => { this._slider1Ref = c; }}
data={data}
renderItem={this.renderSlider}
sliderWidth={width}
itemWidth={(width - 30)}
itemWidth={(width - 30)}
inactiveSlideScale={0.96}
inactiveSlideOpacity={1}
firstItem={0}
enableMomentum={false}
lockScrollWhileSnapping={false}
loop={true}
loopClonesPerSide={100}
autoplay={true}
activeSlideOffset={50}
/>
the comple documentation you can find here and about the plugin api you can find here.
Please anyone help me.
Thanks.
I had the same issue when loop={true} was set.
We came up with this workaround:
We maintained the activeSlide value in a state, and created a reference of Carousel refCarousel.
const [activeSlide, setActiveSlide] = useState(0);
const refCarousel = useRef();
Then we added code in useEffect to manually move the carousel item to the first one back when it reaches the end with a delay of 3500 milliseconds which is also set to autoplayInterval props.
This way, we achieved the looping effect.
useEffect(() => {
if (activeSlide === data.length - 1) {
setTimeout(() => {
refCarousel.current.snapToItem(0);
}, 3500)
}
}, [activeSlide]);
Below is the Carousel component declaration. Only the relevant props are shown here.
<Carousel
ref={refCarousel}
...
//loop={true}
autoplay={true}
autoplayDelay={500}
autoplayInterval={3500}
onSnapToItem={(index) => setActiveSlide(index)}
/>
use React Native Fast Image if you are facing blinking issue.

How to show a List item after click button in react native

I'm a new to react-native and i need a help. I want to do this: I have a button, when click it, a list item will show under the button. Help me guys !
Thanks
I suggest you to use or learn (if you want make your own popover) from react-native-list-popover. Here some screenshot from reace-native-list-popover:
Make a Boolean flag in your component state and initiate it with false and then use it for showing the list. You can use FlatList for make a good list.
The example code can be like this:
export default class ClassName extends Component {
state = {showList: false}
_onPress = () => {
this.setState({showList: true})
}
render() {
return (
<View>
<Button onPress={this._onPress}>Show List</Button>
{(this.state.showList) && <FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <Text>{item.key}</Text>}
/>}
</View>
)
}
}

scrolltoTop not working in Animated.scrollView

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});
}
}}