【问题标题】:Conditional Render vs TabNavigator条件渲染 vs TabNavigator
【发布时间】:2018-03-01 21:25:23
【问题描述】:

案例是我有三个屏幕,显示从 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 为所有屏幕呈现一次,仅此而已)

我怎样才能结合这两种方法并拥有干净的代码和最新的屏幕?

【问题讨论】:

  • "如果用户切换屏幕,即使用户没有在任何屏幕上发送任何操作,应用程序也会获取并使用网络";如果唯一的 fetch 是在父组件的componentWillMount 上,那么这不是真的......
  • react-navigation 中的 TabNavigator 有一个 lazy 属性
  • 没有。 ComponentWillMount 仅在其父组件第一次渲染时调用一次。 ComponentWillUpdate 是在每个 setState 上调用的钩子。
  • 所以不要那样做?如果您只想获取一次,请在ComponentWillMount 中执行此操作。
  • 然后,这些用户操作应该触发一个处理函数,该函数会调度您需要的任何 fetch 调用。除非您希望它们在这些生命周期钩子上触发,否则不应将它们打包在生命周期钩子中。用户输入!= 生命周期。

标签: javascript reactjs react-native render tabnavigator


【解决方案1】:

响应 cmets 中发生的讨论;

看起来您真正想要的是一个可以触发特定用户操作更新的处理函数。这在某种程度上符合您的“条件渲染”设计模式。我会举个例子,但非常简化;

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内渲染的按钮时会额外调用一次。组件的任何其他更新或重新渲染都不会导致重新获取。

您可以继续将此扩展到应触发重新获取的其他用户操作,例如输入字段的onFocusonBlur

【讨论】:

    猜你喜欢
    • 2018-12-13
    • 2017-08-22
    • 2017-08-17
    • 2017-10-19
    • 1970-01-01
    • 2021-08-01
    • 2020-10-12
    • 2012-11-28
    • 2021-05-22
    相关资源
    最近更新 更多