条件渲染与 TabNavigator
Conditional Render vs TabNavigator
案例是我有三个屏幕,显示从 API 获取的结果,并允许用户对这些结果调度操作。这些操作会触发(应该)在其他两个屏幕中产生结果。换句话说,如果用户在任何屏幕上执行某些操作,其他两个屏幕应该更新。
例如,屏幕 A、B 和 C。我可以采用以下两种方法之一:
- 条件渲染:
class MainScreen extends Component {
state: Object;
constructor(props) {
super(props);
this.state = { currentActiveScreen: 1 }
}
componentWillMount()
{
this.retrieveResultForScreenA();
this.retrieveResultForScreenB();
this.retrieveResultForScreenC();
}
retrieveResultForScreenA()
{
// get results from API
}
retrieveResultForScreenB()
{
// get results from API
}
retrieveResultForScreenC()
{
// get results from API
}
ChangeScreen(screen_number)
{
this.setState({currentActiveScreen: screen_number});
}
render()
{
if(this.state.currentActiveScreen === 1)
{
// render screen A results
// along with a tab bar to switch screens:
<View style={{flexDirection: "row"}}>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 1) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 2) }}>
<Text>ScreenB</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 3) }}>
<Text>ScreenC</Text>
</TouchableOpacity>
</View>
}
if(this.state.currentActiveScreen === 2)
{
// render screen B results
// along with a tab bar to switch screens:
<View style={{flexDirection: "row"}}>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 1) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 2) }}>
<Text>ScreenB</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 3) }}>
<Text>ScreenC</Text>
</TouchableOpacity>
</View>
}
if(this.state.currentActiveScreen === 3)
{
// render screen C results
// along with a tab bar to switch screens:
<View style={{flexDirection: "row"}}>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 1) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 2) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 3) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
</View>
}
}
}
- 三屏TabNavigator:
class ScreenA extends Component {
static navigationOptions = ({ navigation }) => ({ title: 'ScreenA' });
constructor(props) {
super(props);
}
componentWillMount()
{
this.retrieveResultForScreenA();
}
retrieveResultForScreenA()
{
// get results from API
}
render() {
return (
// render screen A results
);
}
}
class ScreenB extends Component {
static navigationOptions = ({ navigation }) => ({ title: 'ScreenB' });
constructor(props) {
super(props);
}
componentWillMount()
{
this.retrieveResultForScreenB();
}
retrieveResultForScreenA()
{
// get results from API
}
render() {
return (
// render screen B results
);
}
}
class ScreenC extends Component {
static navigationOptions = ({ navigation }) => ({ title: 'ScreenC' });
constructor(props) {
super(props);
}
componentWillMount()
{
this.retrieveResultForScreenC();
}
retrieveResultForScreenA()
{
// get results from API
}
render() {
return (
// render screen C results
);
}
}
const MainScreen = TabNavigator({
ScreenA: { screen: MyScreenA },
ScreenB: { screen: MyScreenB },
ScreenC: { screen: MyScreenC },
});
第一种方法的问题在于:
- 如果用户切换屏幕,应用程序将获取并使用网络,即使用户没有在任何屏幕上发送任何操作也是如此
第二种方法的问题在于:
- 其他选项卡不会在任何已调度的操作上更新(tabNavigator 为所有屏幕呈现一次,仅此而已)
如何结合这两种方法并获得干净的代码和最新的屏幕?
回应评论中的讨论;
看来您真正想要的是一个可以触发特定用户操作更新的处理函数。这在某种程度上符合您的 "Conditional Render" 设计模式。我举个例子,但是非常简单;
class MainScreen extends Component {
state: Object;
constructor(props) {
super(props);
this.state = { currentActiveScreen: 1 }
}
componentWillMount() {
this.handleFetchRequest();
}
getTabSelection() {
return (
//some JSX with links that controls `state.currentActiveScreen`
);
}
handleFetchRequest() {
this.retrieveResultForScreenA();
this.retrieveResultForScreenB();
this.retrieveResultForScreenC();
}
getCurrentScreen() {
if(this.state.currentActiveScreen === 1) {
return <ScreenA onFetchRequest={this.handleFetchRequest}/>;
}
if(this.state.currentActiveScreen === 2) {
return <ScreenB onFetchRequest={this.handleFetchRequest}/>;
}
if(this.state.currentActiveScreen === 3) {
return <ScreenC onFetchRequest={this.handleFetchRequest}/>;
}
}
render() {
return <div>
{this.getTabSelection()}
{this.getCurrentScreen()}
</div>;
}
}
class ScreenA extends Component {
render() {
return <button onClick={this.props.onFetchRequest}/>;
}
}
所以在上面的例子中,组件会在组件第一次挂载时调用一次handleFetchRequest
,然后当用户点击ScreenA
内渲染的按钮时会额外调用一次。组件的任何其他更新或重新呈现都不会导致重新获取。
您可以继续将此扩展到应触发重新获取的其他用户操作,例如输入字段的 onFocus
或 onBlur
。
案例是我有三个屏幕,显示从 API 获取的结果,并允许用户对这些结果调度操作。这些操作会触发(应该)在其他两个屏幕中产生结果。换句话说,如果用户在任何屏幕上执行某些操作,其他两个屏幕应该更新。
例如,屏幕 A、B 和 C。我可以采用以下两种方法之一:
- 条件渲染:
class MainScreen extends Component {
state: Object;
constructor(props) {
super(props);
this.state = { currentActiveScreen: 1 }
}
componentWillMount()
{
this.retrieveResultForScreenA();
this.retrieveResultForScreenB();
this.retrieveResultForScreenC();
}
retrieveResultForScreenA()
{
// get results from API
}
retrieveResultForScreenB()
{
// get results from API
}
retrieveResultForScreenC()
{
// get results from API
}
ChangeScreen(screen_number)
{
this.setState({currentActiveScreen: screen_number});
}
render()
{
if(this.state.currentActiveScreen === 1)
{
// render screen A results
// along with a tab bar to switch screens:
<View style={{flexDirection: "row"}}>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 1) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 2) }}>
<Text>ScreenB</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 3) }}>
<Text>ScreenC</Text>
</TouchableOpacity>
</View>
}
if(this.state.currentActiveScreen === 2)
{
// render screen B results
// along with a tab bar to switch screens:
<View style={{flexDirection: "row"}}>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 1) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 2) }}>
<Text>ScreenB</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 3) }}>
<Text>ScreenC</Text>
</TouchableOpacity>
</View>
}
if(this.state.currentActiveScreen === 3)
{
// render screen C results
// along with a tab bar to switch screens:
<View style={{flexDirection: "row"}}>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 1) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 2) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{ this.ChangeScreen.bind(this, 3) }}>
<Text>ScreenA</Text>
</TouchableOpacity>
</View>
}
}
}
- 三屏TabNavigator:
class ScreenA extends Component {
static navigationOptions = ({ navigation }) => ({ title: 'ScreenA' });
constructor(props) {
super(props);
}
componentWillMount()
{
this.retrieveResultForScreenA();
}
retrieveResultForScreenA()
{
// get results from API
}
render() {
return (
// render screen A results
);
}
}
class ScreenB extends Component {
static navigationOptions = ({ navigation }) => ({ title: 'ScreenB' });
constructor(props) {
super(props);
}
componentWillMount()
{
this.retrieveResultForScreenB();
}
retrieveResultForScreenA()
{
// get results from API
}
render() {
return (
// render screen B results
);
}
}
class ScreenC extends Component {
static navigationOptions = ({ navigation }) => ({ title: 'ScreenC' });
constructor(props) {
super(props);
}
componentWillMount()
{
this.retrieveResultForScreenC();
}
retrieveResultForScreenA()
{
// get results from API
}
render() {
return (
// render screen C results
);
}
}
const MainScreen = TabNavigator({
ScreenA: { screen: MyScreenA },
ScreenB: { screen: MyScreenB },
ScreenC: { screen: MyScreenC },
});
第一种方法的问题在于:
- 如果用户切换屏幕,应用程序将获取并使用网络,即使用户没有在任何屏幕上发送任何操作也是如此
第二种方法的问题在于:
- 其他选项卡不会在任何已调度的操作上更新(tabNavigator 为所有屏幕呈现一次,仅此而已)
如何结合这两种方法并获得干净的代码和最新的屏幕?
回应评论中的讨论;
看来您真正想要的是一个可以触发特定用户操作更新的处理函数。这在某种程度上符合您的 "Conditional Render" 设计模式。我举个例子,但是非常简单;
class MainScreen extends Component {
state: Object;
constructor(props) {
super(props);
this.state = { currentActiveScreen: 1 }
}
componentWillMount() {
this.handleFetchRequest();
}
getTabSelection() {
return (
//some JSX with links that controls `state.currentActiveScreen`
);
}
handleFetchRequest() {
this.retrieveResultForScreenA();
this.retrieveResultForScreenB();
this.retrieveResultForScreenC();
}
getCurrentScreen() {
if(this.state.currentActiveScreen === 1) {
return <ScreenA onFetchRequest={this.handleFetchRequest}/>;
}
if(this.state.currentActiveScreen === 2) {
return <ScreenB onFetchRequest={this.handleFetchRequest}/>;
}
if(this.state.currentActiveScreen === 3) {
return <ScreenC onFetchRequest={this.handleFetchRequest}/>;
}
}
render() {
return <div>
{this.getTabSelection()}
{this.getCurrentScreen()}
</div>;
}
}
class ScreenA extends Component {
render() {
return <button onClick={this.props.onFetchRequest}/>;
}
}
所以在上面的例子中,组件会在组件第一次挂载时调用一次handleFetchRequest
,然后当用户点击ScreenA
内渲染的按钮时会额外调用一次。组件的任何其他更新或重新呈现都不会导致重新获取。
您可以继续将此扩展到应触发重新获取的其他用户操作,例如输入字段的 onFocus
或 onBlur
。