DEV Community

Michael Lustig - halfjew22@gmail.com
Michael Lustig - halfjew22@gmail.com

Posted on • Updated on

I’m Creating a Deep Dive for React Native into Creating Lists With Functionality That You Will Inevitably Encounter.

MANDATORY: Preview of the end result.

TL;DR: Where is the video link

I DON’T LIKE VIDEOS: Just show me the code

I DON’T LIKE VIDEOS OR READING CODE: Where is your Medium writeup

I cheated and didn’t write anything up on Medium, but if you subscribe and complain to me that that is something you’d like to see, well, supply and demand!

Recently in React (which React Native uses), the team has released a really cool set of functionality called Hooks. Hooks allow us to create shared functionality that can abstract away a lot of complexity. In this tutorial series, I’m going to start with the most basic list you can create (provided by the example documentation here) and transform it into something that does a whole bunch of really cool stuff, including:

  • Infinite Scrolling with pagination
  • Live updates that sync with your list state from a remote data source (I use and show you how to use Firestore)
  • Optimistic list item updates
  • Live updating counters within each List Item that will show a ‘timer’ of sorts for how long ago a list item was created
  • Staging of new posts (kind of like how Twitter will ask if you want to ‘load more tweets’ as they arrive’)
  • Scrolling to top of list programmatically
  • Using Fakerjs to easily create testing data

… and probably more!

I don’t edit away the mistakes because I truly think that takes away from learning opportunities. A lot of tutorial content out there is so perfectly done and cookie cutter that I feel it leaves the viewer with the idea that “I woke up like this”, when in reality that is rarely the case.

Hopefully you enjoy, here’s the Playlist URLand some other links if you liked the video. Please do let me know if there’s anything list related that you’d like to learn about and I’ll try and bake it into one of the videos.

YouTube | dev.to | Twitter | Github | Medium | Reddit

Code (since it's still short and self contained)

import React, {useState, useRef, useMemo} from 'react';
import {
  SafeAreaView,
  TouchableOpacity,
  FlatList,
  TextInput,
  Button,
  Alert,
  View,
  StyleSheet,
  Text,
} from 'react-native';

const DATA = [
  {
    id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
    title: 'First Item',
    selected: false,
  },
  {
    id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
    title: 'Second Item',
    selected: false,
  },
  {
    id: '58694a0f-3da1-471f-bd96-145571e29d72',
    title: 'Third Item',
    selected: false,
  },
];

function Item({item: {id, title, selected}, onSelect}) {
  console.log('L29 "item is rendering" ===', id);

  return (
    <TouchableOpacity
      onPress={() => onSelect(id)}
      style={[
        styles.item,
        {backgroundColor: selected ? '#6e3b6e' : '#f9c2ff'},
      ]}>
      <View>
        <Text style={styles.title}>{title}</Text>

        <Button title="Like Post" onPress={() => {}} />

        <Button title="Dislike Post" onPress={() => {}} />
      </View>
    </TouchableOpacity>
  );
}

function ItemPureFunctional({item: {id, title, selected}, onSelect}) {
  return useMemo(() => {
    console.log('L44 "item is rendering" ===', id);
    return (
      <TouchableOpacity
        onPress={() => onSelect(id)}
        style={[
          styles.item,
          {backgroundColor: selected ? '#6e3b6e' : '#f9c2ff'},
        ]}>
        <View>
          <Text style={styles.title}>{title}</Text>

          <Button title="Like Post" onPress={() => {}} />

          <Button title="Dislike Post" onPress={() => {}} />
        </View>
      </TouchableOpacity>
    );
  }, [id, onSelect, selected, title]);
}

class ItemPureComponent extends React.PureComponent {
  render() {
    return (
      <TouchableOpacity
        onPress={() => this.props.onSelect(this.props.id)}
        style={[
          styles.item,
          {backgroundColor: this.props.selected ? '#6e3b6e' : '#f9c2ff'},
        ]}>
        <Text style={styles.title}>{this.props.title}</Text>
      </TouchableOpacity>
    );
  }
}

export default function App() {
  const [data, setData] = useState(DATA);
  const [text, setText] = useState('');

  const onSelect = useRef(id => {
    setData(oldData => {
      return [
        ...oldData.map(item => {
          if (id === item.id) {
            return {
              ...item,
              selected: !item.selected,
            };
          }
          return item;
        }),
      ];
    });
  });

  const changeTextOfSecondItem = newtext => {
    setData(oldData => {
      return [
        ...oldData.map(item => {
          if (item.id === '3ac68afc-c605-48d3-a4f8-fbd91aa97f63') {
            return {
              ...item,
              title: newtext,
            };
          }
          return item;
        }),
      ];
    });
  };

  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={data}
        renderItem={({item}) => (
          <ItemPureFunctional item={item} onSelect={onSelect.current} />
        )}
        keyExtractor={item => item.id}
      />
      <TextInput
        placeholder={'Enter some data'}
        style={{height: 40, borderColor: 'gray', borderWidth: 1}}
        onChangeText={setText}
        value={text}
      />
      <Button
        title="Change the text of the second list item"
        color="#f194ff"
        onPress={() => {
          changeTextOfSecondItem(text);
          setText('');
        }}
      />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 24,
  },
  item: {
    backgroundColor: '#f9c2ff',
    padding: 20,
    marginVertical: 8,
    marginHorizontal: 16,
  },
  title: {
    fontSize: 32,
  },
});
Enter fullscreen mode Exit fullscreen mode

Top comments (0)