loading...

✅useContext ✅ to Update State in List from Detail View (React Native)

technoplato profile image Michael Lustig - halfjew22@gmail.com ・3 min read

FOLLOW ME: YouTube | dev.to | Twitter | Github | Medium | Reddit

Video

✅useContext ✅Use React Context to Update State in List from Detail View (React Native)

Brief Intro

I came across a post this morning on Reddit asking about how to update state in their list from their details page. I thought this would be a good video to make, explaining how to do this in a couple of different ways. I ended up only making the video demonstrating how to use React Context to do this, which is slightly more complex code, but I feel cleaner ultimately.

Run the code in your browser: Context | Callbacks

Snack (run and tinker with code IN YOUR BROWSER 🤯 | | Reddit Post

SHUTUP, WHERES THE CODE

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

import { createAppContainer } from 'react-navigation';  
import { createStackNavigator } from 'react-navigation-stack';  

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

const DataContext = createContext({  
  data: [],  
  selectItem: () => {},  
});  

const DataContextProvider = props => {  
  const selectItem = id => {  
    const item = state.data[id];  
    item.selected = !item.selected; 
      ...state,  
      data: {  
        ...state.data,  
        [item.id]: item,  
      },  
    });  
  };  

  const initialState = {  
    data: DATA,  
    selectItem: selectItem,  
  };  

  const [state, setState] = useState(initialState);  

  return (  
    <DataContext.Provider value={state}>{props.children}</DataContext.Provider>  
  );  
};  

const Main = ({ navigation }) => {  
  const { data } = useContext(DataContext);  

  return (  
    <SafeAreaView style={styles.container}>  
      <FlatList  
        data={Object.values(data)}  
        renderItem={({ item }) => (  
          <Item  
            item={item}  
            handleShowDetails={id => {  
              navigation.navigate('Details', {  
                id,  
              });  
            }}  
          />  
        )}  
       keyExtractor={item => item.id}  
      />  
    </SafeAreaView>  
  );  
};  

function Item({ item, handleShowDetails }) {  
  const { id, title, selected } = item;  
  const { selectItem } = useContext(DataContext);  
  return useMemo(() => {  
    return (  
      <TouchableOpacity  
        onPress={() => {  
          selectItem(id);  
        }}  
        style={[  
          styles.item,  
          { backgroundColor: selected ? '#6e3b6e' : '#f9c2ff' },  
        ]}>  
        <View  
          style={{  
            flexDirection: 'row',  
            justifyContent: 'space-between',  
            padding: 18,  
          }}>  
          <Text style={styles.title}>{title}</Text>  
          <Text onPress={() => handleShowDetails(id)}>Details</Text>  
        </View>  
      </TouchableOpacity>  
    );  
  }, [selected, title]);  
}  

const Details = ({ navigation }) => {  
  const id = navigation.state.params.id;  
  const { data, selectItem } = useContext(DataContext);  
  const item = data[id];  

  return (  
    <View  
      style={[  
        styles.centered,  
        { backgroundColor: item.selected ? '#6e3b6e' : '#f9c2ff' },  
      ]}>  
      <Text style={styles.title}>{`Details for Item: ${item.title}`}</Text>  
      <Text  
         onPress={() => {  
          selectItem(item.id);  
        }}>{`Is selected: ${item.selected}\n\n(click me to toggle selected)`}</Text>  
    </View>  
  );  
};  

const StackNavigation = createStackNavigator({  
  Main: Main,  
  Details: Details,  
});  

const Container = createAppContainer(StackNavigation);  

const App = () => (  
  <DataContextProvider>  
    <Container />  
  </DataContextProvider>  
);  

export default App;  

const styles = StyleSheet.create({  
  centered: {  
    flex: 1,  
    justifyContent: 'center',  
    alignItems: 'center',  
    padding: 16,  
  },  
  title: {  
    fontSize: 32,  
    fontWeight: '400',  
  },  
  container: {  
    flex: 1,  
    marginTop: 24,  
  },  
  item: {  
    backgroundColor: '#f9c2ff',  
    padding: 20,  
    marginVertical: 8,  
    marginHorizontal: 16,  
  },  
});

🤟🙏 THANKS FOR READING 🤟🙏

If you liked the post, please be sure to give it a thumbs up, a heart, an upvote, a retweet, or whatever it is that the cool kids do these days. All my follow links are below if you're intersted in quick tutorials and explanations like this one.

🤔 QUESTIONS | 📝 COMMENTS | 📉 CONCERNS | 📩 SUGGESTIONS

Let me know if you have any questions in the comments or if I could have done a better job explaining anything anywhere.

Most importantly,
💻📲👨🏻‍💻KEEP CODING, KEEP LEARNING, AND KEEP DOING!

👇👇👇 FOLLOW ME 👇👇👇

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

Discussion

markdown guide
 

Hey Michael, great article! I was wondering how you would have implemented the feature to add another object to DATA, and have it update the list. Would it be possible to do this without re-rendering the whole DATA?

 

Thanks a lot! Adding another data item to DATA should already work without re-rendering the rest of the Components in the list because within the render method of the list item, we're using useMemo and only re-rendering those when title or selected changes.

Try modifying the example and let me know if you run into any issues.