Reputation: 51
Sorry if this is a bit of a noob question. I'm trying to set up a react-native multiplayer game with a lobby which shows who your opponents are. The problem is that even when the prop representing the opponents updates, the component does not re-render, even though a console log shows me the prop has changed (and that render() was called?). Some snippets from my code are below:
In Lobby.js:
export default class Lobby extends Component {
render() {
console.log('In Lobby, opponents = ' + this.props.opponents);
return(
<View style={{ flex: 1, justifyContent: "center", alignItems: 'center' }}>
<Text>Welcome to the lobby { this.props.username }!</Text>
<Text>Opponents: { this.props.opponents }</Text>
... more text and buttons ...
</View>
);
}
}
As I said, I can see in the console that this.props.opponents
does change but the screen doesn't seem to re-render that <Text>
component. I initially thought this may be because this.props.opponents
is set to the opponents
value of my Main component's state, but the console log seems to debunk this.
I've looked here on SO and found suggestions to add shouldComponentUpdate()
and componentDidUpdate()
to my component but the nextProps
parameter would always actually be the same as this.props
. I.e. if I add:
shouldComponentUpdate(nextProps) {
console.log('this.props.opponents=' + this.props.opponents + '; ' + 'nextProps.opponents=' + nextProps.opponents);
return this.props.opponents != nextProps.opponents;
}
This never actually returns True for me, even though the prop is definitely changing. (I also don't know what code I would actually want in componentDidUpdate() either, since I just want it to re-render). It just shows that, yes the prop is different but that both nextProps.opponents
and this.props.opponents
have changed to that same new value (i.e. 'TestUser').
I'm really at a loss here. Thanks in advance.
App.js:
import React, { Component } from 'react';
import Main from './components/Main';
export default function App() {
return (
<Main/>
)
}
In Main.js:
import React, { Component } from 'react';
import { View } from 'react-native';
import Lobby from './Lobby';
export default class Main extends Component {
constructor(props) {
super(props);
this.state = {
opponents: [], // array of strings of other users' usernames
in_lobby: true // whether user is in lobby or not
};
this.testClientJoin = this.testClientJoin.bind(this);
}
testClientJoin() {
console.log('Called testClientJoin().');
let currentOpponents = this.state.opponents;
currentOpponents.push('TestUser');
this.setState({
opponents: currentOpponents
});
}
render() {
return(
<View style={{ flex: 1}}>
{
this.state.in_lobby &&
<Lobby
opponents={this.state.opponents}
testClientJoin={this.testClientJoin}
/>
}
</View>
);
}
}
In Lobby.js:
import React, { Component } from 'react';
import { View, Button, Text } from 'react-native';
export default class Lobby extends Component {
render() {
console.log('Opponents prop = ' + this.props.opponents);
return(
<View style={{ flex: 1, justifyContent: "center", alignItems: 'center' }}>
<Text>Welcome to the lobby!</Text>
<Text>Your opponents are {this.props.opponents}.</Text>
<Button
title='Add test opponent'
onPress={this.props.testClientJoin}
/>
</View>
);
}
}
So. When I tap the button to Add test opponent, the console logs
Called testClientJoin().
Opponents prop = TestUser
which shows the prop has indeed updated. However, the doesn't actually reflect this change, until I force some update (i.e. since I'm using expo, I just save the file again, and I finally see the text appear on my phone. I'm sure I'm just being an idiot but would love to know how to get the desired behavior of the text component updating.
Upvotes: 1
Views: 2153
Reputation: 51
Well I found an answer to my question which I'll leave here if anyone finds this. What I had to do was the following:
Main.js:
Instead of passing this.state.opponents
directly as a prop to <Lobby>
, pass a copy of this array instead.
render() {
<Lobby
testClientJoin={this.testClientJoin}
opponents={ [...this.state.opponents] }
/>
And this has the desired result. So the moral of the story is, don't try to directly pass an array state from a parent to a child component.
Upvotes: 1