React Native scroll into element

Viktor Chukhlov
3 min readApr 30, 2021

Before you will dive to read my solution I am willing to invite you to my Telegram Channel. Over there you can find good remote job offers. This channel created only for developers.

Let start

Working with React Native sometimes we have to find the way to scroll to the specific element. It’s easy when the scroll and all of needed elements based on the same DOM tree.

Let imagine a case when you have a Drawer Navigation and when you click by specific button the application should close drawer, jump to the needed screen and scroll into specific element. We understand that the button from drawer navigation, scrollview and needed element based on the different DOM trees.

My Solution

class Refs {
private _elements = new Map();

public setRef = (key: string) => (ref: any) => {
this._elements.set(key, ref);
};

public getRef(key: string) {
return this._elements.get(key);
}

public remove(key: string) {
this._elements.delete(key);
}

public clear() {
this._elements.clear();
}
}

export default new Refs();

Now we have a class where we can store a needed elements and and manipulate with them. If you have any questions regarding my Solutions ask me on Telegram Channel!

Let create drawer navigation and try to use setRef method

import React, {FC} from 'react';
import {View, SafeAreaView} from 'react-native';
import Refs from '../../../helpers/refs';
import {
DrawerContentScrollView,
DrawerContentComponentProps,
} from '@react-navigation/drawer';
import DrawerHeader from './drawerHeader';
import DrawerMenu from './drawerMenu';
import DrawerButtons from './drawerButtons';
import styles from './styles';

const DrawerContent: FC<DrawerContentComponentProps> = ({navigation}) => {
Refs.setRef('navigation')(navigation); // set navigation ref

return (
<View style={styles.menu}>
<DrawerContentScrollView>
<DrawerHeader />
<DrawerMenu />
</DrawerContentScrollView>

<SafeAreaView>
<DrawerButtons />
</SafeAreaView>
</View>
);
};

export default DrawerContent;

Will add main scroll to Refs

import React, {FC, useEffect} from 'react';
import {View, SafeAreaView, ScrollView} from 'react-native';
import {DrawerContentComponentProps} from '@react-navigation/drawer';
import Refs from '../../helpers/refs';
import Statistics from '../../components/statistics';
import Header from '../../components/header';
import Goals from '../../components/goals';
import Offers from '../../components/offers';
import styles from './styles';

const Main: FC<DrawerContentComponentProps> = ({navigation}) => {
useEffect(() => {
return () => Refs.remove('scroll'); // remove scroll on unmount
}, []);

return (
<SafeAreaView style={styles.body}>
<ScrollView ref={Refs.setRef('scroll')}> // add scroll to Refs
<View style={styles.statisticsBar} />
<Statistics />
<Header {...navigation} />
<Goals />
<Offers />
</ScrollView>
</SafeAreaView>
);
};

export default Main;

Will add offers element to Refs

import React, {useEffect, useMemo, useContext} from 'react';
import {View} from 'react-native';
import Refs from '../../helpers/refs';
import {TabsContext} from '../../providers/tabs';
import Tabs from '../tabs';
import OffersList from './list';
import styles from './styles';

const OffersView = () => {
const [tab] = useContext(TabsContext);

useEffect(() => {
return () => Refs.remove('offers'); // remove reference link
}, []);

return (
<>
<Tabs />
<View style={styles.offers} ref={Refs.setRef('offers')}> // add offers view element to Refs
<OffersList />
</View>
</>
);
};

export default OffersView;

Trying scroll to element

import Refs from '../../../helpers/refs';const scrollToOffers = () => {
const scroll = Refs.getRef('scroll');
const offers = Refs.getRef('offers');
const navigation = Refs.getRef('navigation');

offers?.measure((x: number, y: number) => {
navigation?.jumpTo('Main');
scroll?.scrollTo({x, y, animated: true});
});
};

Don’t forget to clear map

import React, {useEffect} from 'react';
import Refs from './helpers/refs';
import DrawerNavigation from './stack/drawer';

function App() {
useEffect(() => {
return () => Refs.clear(); // clear whole map from Refs class
}, []);

return (
<DrawerNavigation />
);
}

export default App;

Conclusions

Why I did not use HOCs or hooks to close this task? Because i don’t want to re-render any components. Main goal was to find the way how to scroll from one tree to another tree element. In this case I don’t need any DOM updates, it means we can use links for existing elements and manipulate with them.

Subscribe to my Telegram Channel, here you can find a remote job offers with a high rates.

--

--