在React Native中将容器组件与表示组件分离

时间:2018-11-12 09:24:17

标签: javascript reactjs react-native

我刚刚开始使用react native构建应用,并在名为HomeScreen.js的同一页面上创建了具有视图和登录功能的基本登录功能。但是我已经从网络上阅读了一篇文章,并告诉我最好从视图中分离逻辑代码,这些功能必须在单独的页面上,视图也必须在不同的页面上。请我帮忙怎么做

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Image, ActivityIndicator, Alert} from 'react-native';
import {Icon, Header, Left, Content, Container, Form, Input, Item, Button, Label, Toast} from 'native-base'
import SettingsScreen from './SettingsScreen';



class HomeScreen extends Component{

    constructor(props){
        super(props)
        this.state={
            showLoader: false,
        }
    }


    static navigationOptions={
        header: null,
        drawerIcon:(
            <Image source={require('../assets/imgs/logo.jpg')}
            style={{height:24, width:24}}/>
        )
    }

  render() {
    return (
        <Container>
        <Header>
            <Left>
                <Icon name="ios-menu" onPress={() =>
                  this.props.navigation.toggleDrawer()}/>
            </Left>
        </Header>

        <Content style={{backgroundColor:'white'}}>
        <Content style={{alignContent:"center", top:100}}>

        { <Image  source={require('../assets/imgs/logo.jpg')}
        style={{height:200, width:200, alignSelf:"center"}}/> }

        <Form>
            <Item stackedLabel>
            <Label >
                Username
            </Label>
            <Input onChangeText={(text=>this.setState({userName:text}))} autoCapitalize = 'none'/>
            </Item>

            <Item stackedLabel last>
            <Label >
                Password
            </Label>
            <Input onChangeText={(text=>this.setState({passWord:text}))}  secureTextEntry={true}  />
            </Item>

            <Content style={{padding:20}}>
            <Button onPress={this.userLogin.bind(this)} iconRight block  primary disabled={!this.state.userName} disabled={!this.state.passWord}>
                <Icon name='arrow-forward' />
                <Text style={{color:'white'}}>Login</Text>
            </Button>
            </Content>

            <Content>
                <ActivityIndicator style={{padding:5}}
                animating={this.state.showLoader}
                size="small"
                />
            </Content>

        </Form>

        </Content>
        </Content>
        </Container>
    );
  }

  userLogin(){ 
      this.setState({showLoader: true});
      fetch('http://api_endpoint.com/login.php',{
        method: 'POST',
        body :JSON.stringify({
            username: this.state.userName,
            password: this.state.passWord
          })
      }).then((response)=>{
        return response.json()
      }).then((response)=>{
          console.log(JSON.stringify(response.message))
          this.setState({showLoader: false})
          if(response.message==='0'){
            Toast.show({
                text: "Wrong Username or Password",
                buttonText: "Try Again",
                type: "danger",
                duration: 4000
              })
          }else{
            this.props.navigation.push('Settings');
          }
      }).catch((error) => {
        this.setState({showLoader: false})
        Alert.alert(
            'Error!',
            'Connection Failed, Try again later',
            [
              {text: 'Ok'}
            ],
            { cancelable: false }
          )

      });
  }
}

export default HomeScreen;

2 个答案:

答案 0 :(得分:0)

您已经有了一个不错的开端。请参考Udemy或其他网站上提供的适当视频教程,以获取良好的开始。由于您的问题较为客观,因此我们无法在此处解释全部内容。获得有关redux的知识,因此您可以将逻辑转移到redux reducer和action。也请尝试了解功能组件,您可以在其中移动视图并使主组件变稀。

https://www.udemy.com/react-native-the-practical-guide/?start=0

您可以参加上述课程以获得更多知识。

答案 1 :(得分:0)

在这种情况下,很清楚哪个代码是视图的一部分,哪个代码正在执行AJAX逻辑。 userLogin函数显然不是演示性的;您可以从10英尺远的地方看到该代码与上面的代码完全不同。

但是,它与应用程序的其余部分有点联系,因为它执行与UI相关的事情,例如显示Toast和导航。

分离此代码的一种方法是将函数分为两部分。将AJAX调用移至另一个(非React)文件,并删除与React相关的所有内容。它只会异步返回结果。然后,视图中代码的其余部分可以相应地响应(例如,显示Toast,导航或调用setState)。

下一步可能是将函数的其余部分移到容器组件中。该组件将提供登录功能,并将其结果存储在其自己的状态中。然后它将这些结果的相关部分传递到HomeScreen组件中。像这样:

import HomeScreen from './homeScreen';
import loginUser from '../apiClient';

class HomeScreenContainer extends Component {
  doLogin = () => {
    this.setState({loginInFlight: true});
    loginUser(userName, password)
    .then(result=>
      this.setState({loginInFlight: false, loginResult: result});
      if (result.loginSucceeded) {
        this.props.navigation.push('Settings');
      }
    }).catch((error) => {
        this.setState({showLoader: false, loginError: true})    
    });
  }
  render() {
    return (
      <HomeScreen 
        loginFunction={this.doLogin} 
        showLoader={this.state.loginInFlight} 
        shouldShowToast={this.state.loginResult.invalidLogin} 
        shouldShowError={this.state.loginError} 
      />
    )
}