问题
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 Context
or 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