How to pass “this.state” of a Component to a Screen in React Navigation 5

不羁的心 提交于 2021-02-11 04:34:34

问题


I am new to React Native and I just started learning ReactNavigation.

The app that I'm working at is meant to keep track of players and points while you're playing a board game. Here's the code of App.js:

import * as React from 'react'; 
import {Component} from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { create StackNavigator } from '@react-navigation/stack';
import { Player } from './player';


const Stack = createStackNavigator();


export default class BoardGameApp extends Component{
  constructor(props){
      super(props);
      this.state={ playerTable:[] }
  }


  render(){

    let numOfPlayers = 4
    const totNumOfTerritories = 48

    return (

      <NavigationContainer>
        <Stack.Navigator initialRouteName="Home">
            <Stack.Screen name="Home" component={HomeScreen} />
            
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}



function HomeScreen(){
  
  return(
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Add a new Player" onPress={
          () => this.setState({ playerTable: [
              ...this.state.playerTable,
              { playerName: "whatever"},
           ]
          })}>
      </Button>

      /* this is commented
      {this.state.playerTable.map(
        function(player) {
          return <Player territories={totNumOfTerritories / numOfPlayers} />;
        }
      )}  here the comment ends */

    </View>
  );
}
 

So basically what should happen is that whenever I press the Button, an object consisting of {playerName: "whatever"} should be added to the PlayerTable[] array present in the state of BoardGameApp, and then what I subsequently do is that I map over this array and render a Player component for each object {playerName: "whatever"} present in the array. When all of this was happening inside the App component without using screens everything was fine, but of course it looked awful. Once I started using screens however, when I press the Button on my phone it gives me the error undefined is not an object (evaluating '_this2.setState') because I guess it doesn't recognize what "this" is.

I am learning ReactNative by following the Cs50 course 2018 where "ScreenProps" were still available. I made some research and I think that my answer should be somewhere around Initial Params, React Contextor Redux even if I still don't know these concepts, however whenever I try to look up on the docs or on Youtube, it just gives me way more complicated stuff than just passing a state from an object to a screen. So this is why I ultimately decided to ask this question here.


回答1:


Working Example: Expo Snack

Console Output:

You can solve it using Context API:

import React, { Component, createContext, useContext } from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
// import { Player } from './player';

const Stack = createStackNavigator();

const ParentContext = createContext();

export default class BoardGameApp extends Component {
  constructor(props) {
    super(props);
    this.state = { playerTable: [] };
  }

  addPlayer = (player) => {
    console.log('data added :', [...this.state.playerTable, player]);
    this.setState({
      playerTable: [...this.state.playerTable, player],
    });
  };

  render() {
    let numOfPlayers = 4;
    const totNumOfTerritories = 48;

    return (
      <ParentContext.Provider value={this.addPlayer}>
        <NavigationContainer>
          <Stack.Navigator initialRouteName="Home">
            <Stack.Screen name="Home" component={HomeScreen} />
          </Stack.Navigator>
        </NavigationContainer>
      </ParentContext.Provider>
    );
  }
}

function HomeScreen() {
  const addPlayer = useContext(ParentContext);
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Add a new Player"
        onPress={() => {
          addPlayer({ playerName: 'whatever' });
        }}></Button>
    </View>
  );
}

const styles = StyleSheet.create({});

Old solution which was not the right way according to comment given by @satya so avoid it but I am keeping it in answer for future ref:

import * as React from 'react';
import { Component } from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
// import { Player } from './player';

const Stack = createStackNavigator();

export default class BoardGameApp extends Component {
  constructor(props) {
    super(props);
    this.state = { playerTable: [] };
  }

  addPlayer = (player) => {
    console.log('hi:', [...this.state.playerTable, player]);
    this.setState({
      playerTable: [...this.state.playerTable, player],
    });
  };

  render() {
    let numOfPlayers = 4;
    const totNumOfTerritories = 48;

    return (
      <NavigationContainer>
        <Stack.Navigator initialRouteName="Home">
          <Stack.Screen
            name="Home"
            component={() => <HomeScreen onClick={this.addPlayer} />}
          />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

function HomeScreen({ onClick }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Add a new Player"
        onPress={() => {
          onClick({ playerName: 'whatever' });
        }}></Button>
    </View>
  );
}

const styles = StyleSheet.create({});


来源:https://stackoverflow.com/questions/65530540/how-to-pass-this-state-of-a-component-to-a-screen-in-react-navigation-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!