Laggy scroll experience due to image fetch
See original GitHub issueHello,
I have a weird issue related to refreshing images. This library made a scrolling much nicer however I cannot push production until I fix the following issue. Spending couple of hours everyday to fix with no luck so I hope one of you can help me out. 😃
I have a listing with the following setup:
Item.js // 100% wide, 140px tall blocks with image background and text on it CachedImage.js // storing images on the device using react-native-fs
I tried several things to make the scrolling smooth but it’s not there yet. Implemented shouldComponentUpdate methods as well to reduce unnecessary rendering.
- If I remove the images the scrolling is perfect
- If I remove CachedImage and replace with normal Image component sending the actual CDN URL the scrolling is perfect, although there is a flash when refreshing the images (this is not ideal as there are a lot of images in my app and would eat the mobile bandwidth in a second)
- If I increase renderAheadOffset to a very high number it works perfectly, because there is no rerender
I do think the issue is with the async getCachedPath() function, which returns the cached path based on the url.
CachedImage.js
constructor(props) {
super(props);
this.fetchImage = this.fetchImage.bind(this);
this.state = {
imagePath: null,
};
}
componentDidMount() {
this.fetchImage(this.props);
}
componentWillReceiveProps(nextProps) {
if (this.props.source && nextProps.source &&
!_.isEqual(this.props.source, nextProps.source)
) {
this.fetchImage(nextProps);
}
}
shouldComponentUpdate(nextProps, nextState) {
return this.state.imagePath !== nextState.imagePath;
}
async fetchImage(props) {
const imagePath = await getCachedPath(props.source.uri);
this.setState({ imagePath });
}
render() {
const { imagePath } = this.state;
return <Image source={{ uri: imagePath }} />;
}
getCachedPath (when I’m testing images are cached already so the only async command is await RNFS.exists(path) by that point)
const getCachedPath = async (uri: string): Promise<{ path: string }> => {
// check if url is valid
if (uri.indexOf('http://') === -1 && uri.indexOf('https://') === -1) {
return uri;
}
const origFileName = uri.substring(uri.lastIndexOf('/'), uri.indexOf('?') === -1 ? uri.length : uri.indexOf('?'));
const ext = origFileName.indexOf('.') === -1 ? '.jpg' : origFileName.substring(origFileName.lastIndexOf('.'));
const pathPrefix = Platform.OS === 'android' ? 'file:' : '';
const fileName = `${SHA1(uri)}${ext}`;
const path = `${BASE_DIR}${fileName}`;
const returnPath = `${pathPrefix}${path}`;
const isExist = await RNFS.exists(path);
// check if file exists
if (isExist) {
return returnPath;
}
// TODO: maybe we don't have to do this every time
try {
await RNFS.mkdir(BASE_DIR, { NSURLIsExcludedFromBackupKey: true });
} catch (err) {
fn.notify('CacheManager:CreateDir', err);
}
const downloadOptions = {
fromUrl: uri,
toFile: path,
};
try {
const fileRes = await RNFS.downloadFile(downloadOptions).promise;
if (fileRes.statusCode === 200) {
return returnPath;
}
} catch (err) {
console.log('err', err
}
};
RecyclerListView.js
constructor(props) {
super(props);
this.dataProvider = new DataProvider((r1, r2) => r1 !== r2);
this.layoutProvider = new LayoutProvider(
index => 'Event',
(type, dim) => {
dim.width = width;
dim.height = 140;
}
);
this.state = {
dataProvider: this.dataProvider.cloneWithRows(this.props.data),
};
}
render() {
return (
<RecyclerListView
dataProvider={this.state.dataProvider}
layoutProvider={this.layoutProvider}
rowRenderer={this.rowRenderer}
/>
);
}
Issue Analytics
- State:
- Created 5 years ago
- Comments:5
Top GitHub Comments
I never had that issue before, however my pictures are always the same width and height. Also for the images, I use them as a backgroud so they use position: absolute. I’m not sure if changing the styling will fix your issue. If you share a bit of your code, it might help one of us spot the issue.
@markhomoki - I am facing issue using react-native-fast-image library with recyclerlistview, sometimes my images are not renering with correct aspect ratio while doing scroll (with recycling). Can you please help if you have faced this issue too