So, I have a simple button (TouchableHighlight) calling the following function:
showMovie() {
this.props.navigator.push({
name: 'MovieScreen',
index: 1,
movie: "terminator"
});
}
It works as expected, pushing the MovieScreen scene defined in a different file.
In the MovieScreen constructor I have:
constructor(props) {
super(props);
console.log(this.props.movie);
}
All I get is "undefined".
I tried with: console.log(this.props.passProps.movie); => undefined.
I tried putting the "movie" parameter in a passProps object => undefined.
I can't seem to pass parameters to a scene. If I print this.props I can't find anywhere the "movie" variable, but this.props is there and it contains the navigator object and everything.
Judging from the examples around the web, I'm doing exactly what thousands of people do, with the difference that mine doesn't work.
What I'm doing wrong?
More details as requested
This is how my app is composed:
index.android.js
HomepageScreen.js
MovieScreen.js
index.android.js
class MovieApp extends Component {
render() {
return (
<Navigator
initialRoute={{ name: 'HomepageScreen', title: 'My Initial Scene', index: 0 }}
renderScene={ this.renderScene }
/>
);
}
renderScene(route, navigator) {
if (route.name == 'HomepageScreen') {
return <HomepageScreen navigator={navigator} />
}
if (route.name == 'MovieScreen') {
return <MovieScreen navigator={navigator} />
}
}
}
HomepageScreen.js
export default class HomepageScreen extends Component {
constructor(props) {
super(props);
var navigator = this.props.navigator;
render() {
return(
<TouchableNativeFeedback onPress={this.showMovie.bind(this)}>
<View style={Style.movieButton}>
<Text style={Style.textStyle1}>Asd</Text>
</View>
</TouchableNativeFeedback>
);
}
showMovie() {
this.props.navigator.push({
name: 'MovieScreen',
index: 1,
movie: "terminator"
});
}
}
MovieScreen.js
export default class MovieScreen extends Component {
constructor(props) {
super(props);
console.log(this.props.movie);
}
.....
Try this:
renderScene(route, navigator) {
if (route.name == 'HomepageScreen') {
return <HomepageScreen navigator={navigator} {...route.passProps} />
}
if (route.name == 'MovieScreen') {
return <MovieScreen navigator={navigator} {...route.passProps} />
}
}
And passing the props like this:
this.props.navigator.push({
name: 'MovieScreen',
index: 1,
passProps: {
movie: "terminator"
}
});
Related
I am new in react native and looking if someone could direct me in detail how to pass parameters to a child tab.
I researched already and found that it could be done using screenprops, however none of those gave me a clear understanding on how to use it to pass the parameters. A clean sample code could be beneficial.
It is quite easy you have not look around enough there are lots of packages, I recommend you to use following package, and take a look at following example. Next time research information that you need before you ask something.
import React, { Component } from 'react';
import { TabView, TabBar, SceneMap } from 'react-native-tab-view';
import SceneA from './SceneA';
import SceneB from './SceneB';
class Layout extends Component {
constructor(props) {
super(props);
this.state = {
index: 0,
routes: [
{ key: 'active', title: 'Scene A' },
{ key: 'inactive', title: 'Scene B' },
],
};
this.renderScene = this.renderScene.bind(this);
this.renderLabel = this.renderLabel.bind(this);
this.onTabChange = this.onTabChange.bind(this);
}
onTabChange(index) {
this.setState({ index });
}
// Here you can send props to different tab components
renderScene({ route }) {
if (!route.key) return null;
if (route.key === 'active') {
return <SceneA type="active" />; // SceneA specific props here
}
if (route.key === 'inactive') {
return <SceneB type="inactive" />;
}
}
renderLabel({ route }, props) {
const { index } = this.state;
const selected = route.key === props.navigationState.routes[index].key;
return (
<View>
<Text>
{route.title.toUpperCase()}
</Text>
</View>
);
}
renderTab() {
return (
<TabView
navigationState={this.state}
onIndexChange={this.onTabChange}
renderScene={this.renderScene}
renderTabBar={props => (
<TabBar
{...props}
renderLabel={e => this.renderLabel(e, props)}
/>
)}
/>
);
}
render() {
return (
<View>
{this.renderTab()}
</View>
);
}
}
export default Layout;
I use react-navigation for manage routes. This is my Home component:
class HomeScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: {
firstname: 'John',
avatar: 'john-profile.png',
location: 'Canada',
}
}
}
componentDidMount() {
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
render() {
return (
<View>
<Image src="{this.state.userProfile.avatar}" />
<Text>Firstname: {this.state.userProfile.firstname}</Text>
<Text>Location: {this.state.userProfile.location}</Text>
</View>
);
}
}
And this is the Profile screen:
class ProfileScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: null,
}
}
componentDidMount() {
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
save() {
var userSavedProfile = this.state.userProfile;
userSavedProfile.firstname = "Peter";
userSavedProfile.avatar = "peter-avatar.png";
userSavedProfile.location = "EEUU";
this.setState({userProfile: userSavedProfile});
AsyncStorage.setItem('userProfile', JSON.stringify(this.state.userProfile), () => {});
}
render() {
return (
<View>
<Button title="Save" onPress={() => this.save()} />
</View>
);
}
}
When I save the new user information and I press back button in header (react-navigation) the user profile is old, firstname = John, etc... How update state from Home when user press back button and refresh data?
You can use BackHandler from react-native
https://facebook.github.io/react-native/docs/backhandler.html
You can change state inside function of backhandler
I think that your application would need a state manager, where you could store your user information and access it anywhere in the app. You should take a look at Redux. It would fit your needs and the info in your Home screen would automatically update.
but for anyone who will need this functionality in there react native application here is the solution you can try.
using react navigation.
import {withNavigationFocus} from "react-navigation";
class Profile extends Component {
...
}
export default withNavigationFocus(Profile);
There can be two workarounds check it out -
1 Send callback in params
class HomeScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: {
firstname: 'John',
avatar: 'john-profile.png',
location: 'Canada',
}
}
this.getUserData = this.getUserData.bind(this);
}
componentDidMount() {
this.getUserData;
}
getUserData = () =>{
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
render() {
return (
<View>
<Image src="{this.state.userProfile.avatar}" />
<Text onPress={()=>this.props.navigation.navigate('ProfileScreen', this.getUserData)}>Firstname: {this.state.userProfile.firstname}</Text>
<Text>Location: {this.state.userProfile.location}</Text>
</View>
);
}
}
class ProfileScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: null,
}
}
componentDidMount() {
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
save() {
var userSavedProfile = this.state.userProfile;
userSavedProfile.firstname = "Peter";
userSavedProfile.avatar = "peter-avatar.png";
userSavedProfile.location = "EEUU";
this.setState({userProfile: userSavedProfile});
AsyncStorage.setItem('userProfile', JSON.stringify(this.state.userProfile), () => {});
//this is the magic
this.props.navigation.state.params.getUserData();
}
render() {
return (
<View>
<Button title="Save" onPress={() => this.save()} />
</View>
);
}
}
2 On HomeScreen Constructor add this (Dirty one)
this.props.navigation.addListener(
'didFocus',
payload => {
this.setState({is_updated:true});
}
);
You can use componentDidUpdate(){...} insted componentDidMount(){}
I am building a very basic app for testing react native routing. Here my code...
index.android.js
constructor() {
super();
}
renderScene(route, navigator) {
if(route.name === 'loginPage') {
return <Login navigator={navigator}/>
} else if (route.name === 'homePage') {
alert('**********');
return <Home navigator={navigator}/>
}
}
render() {
return (
<Navigator
initialRoute={{name: 'loginPage' }}
renderScene= {(name) => this.renderScene(name)}
/>
);
}
Login Page
constructor() {
super();
this.navigate = this.navigate.bind(this)
}
navigate(name) {
this.props.navigate.push( {
name
})
}
render() {
return (
<Button
onPress={() => this.apiCalling('homePage')}
title="API Call"
accessibilityLabel="See an informative alert"
/>
);
}
}
but here I am getting error. The error is " undefined is not object ( evaluating 'this.props.navigator.push )
How may I resolve it...?
You are doing "this.props.navigate" while the prop being passed is called "navigator"
I am using a ListItem onPress to navigate to a different route using the code below.
onPress(item) {
this.props.navigator.push({
component: Areas,
passProps: {
new_id: item.new_id,
}
});
}
_renderItem(item) {
return (
<ListItem item={item} onPress={ () => this.onPress(item) }/>
);
}
However, the this.props.new_id is undefined in the next component.
export default class areas extends Component {
constructor(props) {
super(props);
console.log(" UUUU ");
console.log(this.props.new_id);
}
render(){
return (
<Text style={styles.liText}>AAA {this.props.new_id} BBB</Text>
);
}
AppRegistry.registerComponent('areas', () => areas);
Is there anything I am doing incorrectly?
Actually, I found the answer. I looked in renderScene which was not passing the props properly.
I fixed it in the following way:
Initial:
return React.createElement(route.component, { navigator });
To:
return React.createElement(route.component, { ...this.props, ...route.passProps, route, navigator } )
This seems the pass the props.
i'm using a Navigator component and want to pass data from a component to a other.
here is some code.
renderScene(route, navigator) {
var routeId = route.id;
if (routeId === 'SplashPage') {
return (
<SplashPage
navigator={navigator} />
);
}
if (routeId === 'Login') {
return (
<Login
navigator={navigator} />
);
}
if (routeId === 'Home') {
return (
<Home
navigator={navigator} />
);
}
....
I want to pass data from login to home when i click on a button for example
this.props.navigator.replace({
id: 'Home',
passProps: {
currentUser: this.user,
}
})
i would like to get the currentUser in the Home Component. I've tried some code that i found but nothing seem to work.
This is whant i want to do :
class Home extends React.Component {
constructor(props){
super(props);
this.currentUser = ????????
}
If anyone can help me with this i would be grateful.
Thanks
You can set up your renderScene method like this:
renderScene={(route, navigator) => {
return React.createElement(route.component, { ...this.props, ...route.passProps, navigator, route } );
}}
And use it like this:
this.props.navigator.replace({
component: Home,
passProps: {
currentUser: this.user,
}
})
And in Home, you can access currentUser like this:
<Text>{ this.props.currentUser }</Text>
Check out this thread for a more detailed example, but that should work for you.