React-native - 将数据从一个屏幕传递到另一个屏幕
React-native - Passing data from one screen to another
我正在尝试学习如何使用 react-native,所以我安装了一个小应用程序,它从服务器获取用户列表,将其显示在 listview
中,并在其中按一行打开显示用户数据的屏幕。
我设置了一个导航器以从一个屏幕转到另一个屏幕。当按下该行时,我可以打开一个新屏幕,但我不知道如何将数据传递到这个新屏幕。
我在index.android.js
中设置了一个导航器
import React from 'react';
import {
AppRegistry,
Navigator,
} from 'react-native';
import ContactList from './src/containers/ContactList.js';
function MyIndex() {
return (
<Navigator
initialRoute={{ name: 'index', component: ContactList }}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { navigator });
}
return undefined;
}}
/>
);
}
AppRegistry.registerComponent('reactest', () => MyIndex);
首先我显示一个带有按钮和空列表视图的屏幕 (ContactList.js),按下按钮后,我获取一些 JSON 数据用于更新 listview
:
import React, { Component, PropTypes } from 'react';
import {
Text,
View,
TouchableOpacity,
TouchableHighlight,
ListView,
Image,
} from 'react-native';
import styles from '../../styles';
import ContactDetails from './ContactDetails';
const url = 'http://api.randomuser.me/?results=15&seed=azer';
export default class ContactList extends Component {
static propTypes = {
navigator: PropTypes.object.isRequired,
}
constructor(props) {
super(props);
const datasource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
jsonData: datasource.cloneWithRows([]),
ds: datasource,
};
}
_handlePress() {
return fetch(url)
// convert to json
.then((response) => response.json())
// do some string manipulation on json
.then(({ results }) => {
const newResults = results.map((user) => {
const newUser = {
...user,
name: {
title: `${user.name.title.charAt(0).toUpperCase()}${user.name.title.slice(1)}`,
first: `${user.name.first.charAt(0).toUpperCase()}${user.name.first.slice(1)}`,
last: `${user.name.last.charAt(0).toUpperCase()}${user.name.last.slice(1)}`,
},
};
return newUser;
});
return newResults;
})
// set state
.then((results) => {
this.setState({
jsonData: this.state.ds.cloneWithRows(results),
});
});
}
renderRow(rowData: string) {
return (
<TouchableHighlight
onPress={() => {
this.props.navigator.push({
component: ContactDetails,
});
}}
>
<View style={styles.listview_row}>
<Image
source={{ uri: rowData.picture.thumbnail }}
style={{ height: 48, width: 48 }}
/>
<Text>
{rowData.name.title} {rowData.name.first} {rowData.name.last}
</Text>
</View>
</TouchableHighlight>
);
}
render() {
const view = (
<View style={styles.container}>
<TouchableOpacity
onPress={() => this._handlePress()}
style={styles.button}
>
<Text>Fetch results?</Text>
</TouchableOpacity>
<ListView
enableEmptySections
dataSource={this.state.jsonData}
renderRow={(rowData) => this.renderRow(rowData)}
onPress={() => this._handleRowClick()}
/>
</View>
);
return view;
}
}
当按下一行时,它会打开一个新屏幕 ContactDetails.js
,它应该显示用户的数据:
import React, {
} from 'react';
import {
Text,
View,
} from 'react-native';
import styles from '../../styles';
export default function ContactDetails() {
return (
<View style={styles.container}>
<Text>{this.props.title}</Text>
<Text>{this.props.first}</Text>
<Text>{this.props.last}</Text>
</View>
);
}
此时我得到了这个错误:
undefined is not an object (evaluating 'this.props.title')
我试过很多东西,例如:
this.props.navigator.push({
component: ContactDetails,
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
});
或
this.props.navigator.push({
component: ContactDetails,
props: {
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
}
});
或
this.props.navigator.push({
component: ContactDetails,
passProps: {
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
}
});
但是没有用。
我还看到我应该使用 redux。我做错了什么吗?
编辑: 问题在这里:
<TouchableHighlight
onPress={() => {
this.props.navigator.push({
component: ContactDetails,
});
}}
>
我想我应该在那里传递一些参数,但是我上面的尝试都失败了。
还是觉得默认的导航太繁琐了。我强烈建议使用这个库进行路由:https://github.com/aksonov/react-native-router-flux
所以问题似乎出在这里:
<Navigator
initialRoute={{ name: 'index', component: ContactList }}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { navigator });
}
return undefined;
}}
/>
在 renderScene 函数中,您确实收到了路线(并使用 route.component),但您没有传递 route.props 或 route.passProps 或您想要调用的任何内容!从我当时在 Navigator 的源代码中看到的情况来看,您应该拥有创建它时的完整路线对象。所以你应该能够传递你的道具。
例如:
<Navigator
initialRoute={{ name: 'index', component: ContactList }}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { navigator, ...route.props });
}
return undefined;
}}
/>
// push
<TouchableHighlight
onPress={() => {
this.props.navigator.push({
component: ContactDetails,
props: { /* ... */ }
});
}}
>
您也可以设置 redux,但这不是必需的。不过,如果您的应用变得更大,您真的应该考虑使用外部商店!
更新:
还有一个问题
您使用了功能组件。功能组件没有 this
。他们在参数中接收道具。
所以应该是这样的:
export default function ContactDetails(props) {
return (
<View style={styles.container}>
<Text>{props.title}</Text>
<Text>{props.first}</Text>
<Text>{props.last}</Text>
</View>
);
}
替换代码:
<TouchableOpacity
onPress={() => this._handlePress()}
style={styles.button}
>
与:
<TouchableOpacity
onPress={() => this._handlePress()}
style={styles.button}
navigator={navigator} {...route.props}
>
这很好:
this.props.navigator.push({
component: ContactDetails,
props: {
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
}
});
我正在尝试学习如何使用 react-native,所以我安装了一个小应用程序,它从服务器获取用户列表,将其显示在 listview
中,并在其中按一行打开显示用户数据的屏幕。
我设置了一个导航器以从一个屏幕转到另一个屏幕。当按下该行时,我可以打开一个新屏幕,但我不知道如何将数据传递到这个新屏幕。
我在index.android.js
import React from 'react';
import {
AppRegistry,
Navigator,
} from 'react-native';
import ContactList from './src/containers/ContactList.js';
function MyIndex() {
return (
<Navigator
initialRoute={{ name: 'index', component: ContactList }}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { navigator });
}
return undefined;
}}
/>
);
}
AppRegistry.registerComponent('reactest', () => MyIndex);
首先我显示一个带有按钮和空列表视图的屏幕 (ContactList.js),按下按钮后,我获取一些 JSON 数据用于更新 listview
:
import React, { Component, PropTypes } from 'react';
import {
Text,
View,
TouchableOpacity,
TouchableHighlight,
ListView,
Image,
} from 'react-native';
import styles from '../../styles';
import ContactDetails from './ContactDetails';
const url = 'http://api.randomuser.me/?results=15&seed=azer';
export default class ContactList extends Component {
static propTypes = {
navigator: PropTypes.object.isRequired,
}
constructor(props) {
super(props);
const datasource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
jsonData: datasource.cloneWithRows([]),
ds: datasource,
};
}
_handlePress() {
return fetch(url)
// convert to json
.then((response) => response.json())
// do some string manipulation on json
.then(({ results }) => {
const newResults = results.map((user) => {
const newUser = {
...user,
name: {
title: `${user.name.title.charAt(0).toUpperCase()}${user.name.title.slice(1)}`,
first: `${user.name.first.charAt(0).toUpperCase()}${user.name.first.slice(1)}`,
last: `${user.name.last.charAt(0).toUpperCase()}${user.name.last.slice(1)}`,
},
};
return newUser;
});
return newResults;
})
// set state
.then((results) => {
this.setState({
jsonData: this.state.ds.cloneWithRows(results),
});
});
}
renderRow(rowData: string) {
return (
<TouchableHighlight
onPress={() => {
this.props.navigator.push({
component: ContactDetails,
});
}}
>
<View style={styles.listview_row}>
<Image
source={{ uri: rowData.picture.thumbnail }}
style={{ height: 48, width: 48 }}
/>
<Text>
{rowData.name.title} {rowData.name.first} {rowData.name.last}
</Text>
</View>
</TouchableHighlight>
);
}
render() {
const view = (
<View style={styles.container}>
<TouchableOpacity
onPress={() => this._handlePress()}
style={styles.button}
>
<Text>Fetch results?</Text>
</TouchableOpacity>
<ListView
enableEmptySections
dataSource={this.state.jsonData}
renderRow={(rowData) => this.renderRow(rowData)}
onPress={() => this._handleRowClick()}
/>
</View>
);
return view;
}
}
当按下一行时,它会打开一个新屏幕 ContactDetails.js
,它应该显示用户的数据:
import React, {
} from 'react';
import {
Text,
View,
} from 'react-native';
import styles from '../../styles';
export default function ContactDetails() {
return (
<View style={styles.container}>
<Text>{this.props.title}</Text>
<Text>{this.props.first}</Text>
<Text>{this.props.last}</Text>
</View>
);
}
此时我得到了这个错误:
undefined is not an object (evaluating 'this.props.title')
我试过很多东西,例如:
this.props.navigator.push({
component: ContactDetails,
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
});
或
this.props.navigator.push({
component: ContactDetails,
props: {
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
}
});
或
this.props.navigator.push({
component: ContactDetails,
passProps: {
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
}
});
但是没有用。
我还看到我应该使用 redux。我做错了什么吗?
编辑: 问题在这里:
<TouchableHighlight
onPress={() => {
this.props.navigator.push({
component: ContactDetails,
});
}}
>
我想我应该在那里传递一些参数,但是我上面的尝试都失败了。
还是觉得默认的导航太繁琐了。我强烈建议使用这个库进行路由:https://github.com/aksonov/react-native-router-flux
所以问题似乎出在这里:
<Navigator
initialRoute={{ name: 'index', component: ContactList }}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { navigator });
}
return undefined;
}}
/>
在 renderScene 函数中,您确实收到了路线(并使用 route.component),但您没有传递 route.props 或 route.passProps 或您想要调用的任何内容!从我当时在 Navigator 的源代码中看到的情况来看,您应该拥有创建它时的完整路线对象。所以你应该能够传递你的道具。
例如:
<Navigator
initialRoute={{ name: 'index', component: ContactList }}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { navigator, ...route.props });
}
return undefined;
}}
/>
// push
<TouchableHighlight
onPress={() => {
this.props.navigator.push({
component: ContactDetails,
props: { /* ... */ }
});
}}
>
您也可以设置 redux,但这不是必需的。不过,如果您的应用变得更大,您真的应该考虑使用外部商店!
更新:
还有一个问题
您使用了功能组件。功能组件没有 this
。他们在参数中接收道具。
所以应该是这样的:
export default function ContactDetails(props) {
return (
<View style={styles.container}>
<Text>{props.title}</Text>
<Text>{props.first}</Text>
<Text>{props.last}</Text>
</View>
);
}
替换代码:
<TouchableOpacity
onPress={() => this._handlePress()}
style={styles.button}
>
与:
<TouchableOpacity
onPress={() => this._handlePress()}
style={styles.button}
navigator={navigator} {...route.props}
>
这很好:
this.props.navigator.push({
component: ContactDetails,
props: {
title: rowData.name.title,
first: rowData.name.first,
last: rowData.name.last,
}
});