Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifting a state so I can modify it with an onPress

I am trying to figure out how lifting states work. Currently, I am trying to use onPress in a different component to change the state. In the snack demo I provided below, ListHome and MapHome do not respond for some reason, but you will still see what I am trying to accomplish.

I want the map and list "buttons" to accomplish what the "click for this" does.

Demo - No errors with the current implementation, just no response other than the flash from touchable opacity. (Also remember the snack does not respond for some reason. My local device works fine)

EDIT: So to be clear, I want to be able to access and change the state whichComponentToShow from another component. i.e the ListHome Component.

export default class Home extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      visible: true,
      whichComponentToShow: 'Screen1',
    };
  }

  goToMap = () => {
    this.setState({ whichComponentToShow: 'Screen2' });
  };

  render(){
    if(this.state.whichComponentToShow === 'Screen1'){
      return(
       <View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
        
        <ListHome
          renderMap = {this.goToMap.bind(this)}
        />
  }
}
export default class ListHome extends React.Component {
  
goToMap = () => {
  this.props.renderMap();
}

<TouchableOpacity onPress={() => this.goToMap.bind(this)}>
     <View style={styles.conditionalMap}>   
         <View style={{justifyContent: 'center', alignItems: 'center'}}>       
             <Text style={{color: 'black', fontSize: scale(15)}}>
                 Map
             </Text>                  
         </View>
     </View>
</TouchableOpacity>
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { MaterialCommunityIcons } from '@expo/vector-icons';

import VenueDetailsScreen from './screens/VenueDetails';
import CarouselGallary from './screens/Carousel';
import Home from './screens/Home';
import Friends from './screens/Friends';
import Profile from './screens/Profile';

const Tab = createBottomTabNavigator();

function MyTabs() {
  return (
    <Stack.Navigator initialRouteName="Home">
      <Stack.Screen
        name="Home"
        component={Home}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="VenueDetails"
        component={VenueDetailsScreen}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="CarouselGallary"
        component={CarouselGallary}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="Friends"
        component={Friends}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="Profile"
        component={Profile}
        options={{ headerShown: false }}
      />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        initialRouteName="Home"
        screenOptions={{
          tabBarActiveTintColor: '#F60081',
          tabBarInactiveTintColor: '#4d4d4d',
          tabBarStyle: {
            backgroundColor: '#d1cfcf',
            borderTopColor: 'transparent',
          },
        }}>
        <Tab.Screen
          name="Home"
          component={MyTabs}
          options={{
            tabBarLabel: 'Home',
            headerShown: false,
            tabBarIcon: ({ color, size }) => (
              <MaterialCommunityIcons name="home" color={color} size={size} />
            ),
          }}
        />
        <Tab.Screen
          name="Friends"
          component={Friends}
          options={{
            tabBarLabel: 'Friends',
            tabBarIcon: ({ color, size }) => (
              <MaterialCommunityIcons
                name="account-group"
                color={color}
                size={size}
              />
            ),
          }}
        />
        <Tab.Screen
          name="Profile"
          component={Profile}
          options={{
            tabBarLabel: 'Profile',
            tabBarIcon: ({ color, size }) => (
              <MaterialCommunityIcons
                name="account"
                color={color}
                size={size}
              />
            ),
          }}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

const Stack = createStackNavigator();
like image 890
Justin Priede Avatar asked Sep 13 '21 05:09

Justin Priede


People also ask

How to lift a state up in React?

In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it. This is called “lifting state up”. We will remove the local state from the TemperatureInput and move it into the Calculator instead.

How do you change the state of one component from another React?

Sending state/props to another component using the onClick event: So first we store the state/props into the parent component i.e in which component where we trigger the onClick event. Then to pass the state into another component, we simply pass it as a prop.

How do I change state value in React?

To make the state change, React gives us a setState function that allows us to update the value of the state. Calling setState automatically re-renders the entire component and all its child components. We don't need to manually re-render as seen previously using the renderContent function.

How do you bind state in React?

Data binding in React can be achieved by using a controlled input . A controlled input is achieved by binding the value to a state variable and a onChange event to change the state as the input value changes.


Video Answer


1 Answers

What you are trying to achieve is a common use case, which is to update the state in an ancestor component. You essentially have a component tree that looks like this:

enter image description here

You are trying to update the state of the Home component from the ListHome component with the renderMap prop that sets the state of the Home screen. This makes sense, so you have basic principle down, the reason why it is not working is due to a minor mistake in the ListHome component

<View style={styles.conditionalMap}>
  <TouchableOpacity onPress={() => this.goToMap.bind(this)}>
    // In the above line, change to this.goToMap()

    <View style={{ justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ color: 'black', fontSize: scale(15) }}>Map</Text>
    </View>
  </TouchableOpacity>
</View>

This is what the bind method does:

The bind() method creates a new function that, when called, has this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

So the way onPress is currently defined, it will create a new function, but that function is never actually called. Changing this.goToMap.bind(this) to this.goToMap() should solve your problem.

like image 99
joachimwedin Avatar answered Oct 20 '22 09:10

joachimwedin