javascript - Hur byter man vyer inom samma skärm (React Native)?


Jag vill duplicera följande med react-native-scrollable-tab-view:

För närvarande är min kod följande, men jag är inte säker på hur jag ska köra och integrera modulen för att göra saker enklare - har någon några idéer om hur jag kan implementera detta? (Jag är nybörjare så all hjälp uppskattas):

Detta är huvudvyn (flikvy):

'use strict';

var React = require('react-native');
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
var Icon = require('react-native-vector-icons/FontAwesome');
var Restaurants = require('../Helpers/Restaurants');
var More = require('../Helpers/More');
var api = require('../Api/Api');
var Profile = require('../Helpers/Profile');
var Recipes = require('../Helpers/Recipes');
var Actions = require('react-native-router-flux').Actions;
var Home = require('../Helpers/Home');

var {
  StyleSheet,
  Text,
  View,
  Image, 
  TabBarIOS,
  Component
} = React;


class Main extends React.Component{
  constructor(props) {
    super(props);
    this.state = {
      selectedTab: 'home',
      notifCount: 0,
      presses: 0,
    };
  }

  GoBack() {
    this.props.navigator.pop();
  }

  render() {
    return (
      <TabBarIOS 
        tintColor="#49B64D"
        barTintColor="rgba(255,255,255,0.3)"
        selectedTab={this.state.selectedTab}>
        <Icon.TabBarItem
          selected={this.state.selectedTab === 'home'}
          icon={require('image!homeicon')}
          onPress={() => {
              this.setState({
                  selectedTab: 'home',
              });
          }}>
            <Home/>
        </Icon.TabBarItem>
        <Icon.TabBarItem
          selected={this.state.selectedTab === 'restaurants'}
          icon={require('image!nomicon')}
          onPress={() => {
                this.setState({
                    selectedTab: 'restaurants',
                });
          }}>
          <Restaurants/>
        </Icon.TabBarItem>
       <Icon.TabBarItem
          selected={this.state.selectedTab === 'recipes'}
          icon={require('image!haticon')}
          onPress={() => {
                this.setState({
                    selectedTab: 'recipes',
                });
          }}>
          <Recipes/>
        </Icon.TabBarItem>
        <Icon.TabBarItem
          selected={this.state.selectedTab === 'profile'}
          icon={require('image!accounticon')}
          onPress={() => {
                this.setState({
                    selectedTab: 'profile',
                });
          }}>
          <Profile/>
        </Icon.TabBarItem>
      </TabBarIOS>
    );
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'transparent'
  },
  bgImage: {
    flex: 1,
    width: window.width,
    resizeMode: 'cover',
  },
});

module.exports = Main;

Detta är receptvyn när du klickar på receptfliken:

'use strict';
var React = require('react-native');
var Seperator = require('./Seperator');
var api = require('../Api/Api');
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
var LinearGradient = require('react-native-linear-gradient');
var Swipeout = require('react-native-swipeout');
var List = require('./List');
var RecipeDetails =  require('./RecipeDetails');
var Actions = require('react-native-router-flux').Actions;


var {
  ScrollView,
  Text,
  View,
  TouchableHighlight,
  StyleSheet,
  Image,
  ListView,
  NavigatorIOS,
} = React;

var styles = StyleSheet.create({
  description: {
    fontSize: 20,
    textAlign: 'center',
    color: '#FFFFFF'
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'transparent',
  },
  linearGradient: {
    flex: 1,
    paddingLeft: 15,
    paddingRight: 15,
    borderRadius: 5,
    opacity: 0.9,
    height: window.width,
  },
  dietText: {
    color:'white',
    fontFamily: 'Avenir Next', 
    alignSelf:'center',
  },
  title: {
    textAlign:'left', 
    marginTop: (window.width/1.4), 
    fontSize: 20, 
    color: 'white', 
    fontFamily: 'Avenir Next', 
    fontWeight: '500',
  },
  dietbuble: {
    backgroundColor:'transparent', 
    height:20, 
    width:60, 
    borderRadius: 10, 
    backgroundColor:'#49B64D',
    marginRight:5,
  },
  nombtn: {
    height: 30,
    width: 30,
    marginBottom: 5,
  }, 
  arrow: {
    height: 15,
    width: 15,
    marginRight: 20,
    marginTop: 5,
  }, 
  upvotenum: {
    marginRight: 5, 
    fontSize: 20, 
    fontWeight: "600",
    color: 'white',
    fontFamily: 'Avenir Next'
  }, 
  dish_num: {
    backgroundColor:'#49B64D',
    height: 30,
    width: 100,
    marginLeft: window.width/1.36,
    borderRadius: 5,
  },
  dishtext: {
    fontFamily: "Avenir Next",
    fontSize: 20,
    fontWeight: "400",
    textAlign: 'center',
    color:"white",
  },
  profilebubble: {
    width: 40,
    height: 40,
    borderRadius: 20,
    margin: 2,
  }
});

var list = [
  {
    component: <List/>
  }
]

class Recipes extends React.Component{

  constructor(props) {
    super(props);
    this.state = {
      venues: new Object(),
    };
  }

  activateHome() {
    api.getAnything(this.props.paleo,this.props.vegan,this.props.vegetarian,this.props.healthy,this.props.dairyfree,this.props.nutfree,this.props.glutenfree)
      .then((res) => {
        console.log(res);
        return res;
    });
  }

  detailsRecipe() {
    this.props.navigator.push ({
        component: RecipeDetails,
        title: "",
    })
  }

  render(){ 

    return (
      <ScrollView
        alwaysBounceVertical={true}
        scrollEventThrottle={200}>
        <Swipeout right={list}>
            <View style={styles.container}>
                <Image source={{uri: 'http://i.huffpost.com/gadgets/slideshows/404432/slide_404432_5031844_free.jpg'}} style={{width: window.width, height: window.width}}>
                  <View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
                    <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                      <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                        <Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
                        <Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
                      </View>
                    </View>
                    <LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
                        <TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
                          <View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
                            <Text style={styles.title}>Recipe Name | 10 Mins</Text>
                          </View>
                        </TouchableHighlight>
                        <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegan</Text>
                           </View>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegie</Text>
                           </View>
                           <View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
                             <Text style={styles.upvotenum} >20</Text>
                             <Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
                             <Image style={styles.nombtn} source={require('image!nombtn')}></Image>
                            </View>
                        </View>
                      </LinearGradient>
                    </View>
                </Image>
            </View>
        </Swipeout>
        <Seperator/>
        <Swipeout right={list}>
            <View style={styles.container}>
                <Image source={{uri: 'http://www.funkinutt.com/wp-content/uploads/2013/06/Vegan-Scallops-Sophies-Kitchen.jpg'}} style={{width: window.width, height: window.width}}>
                  <View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
                    <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                      <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                        <Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
                        <Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
                      </View>
                    </View>
                    <LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
                        <TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
                          <View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
                            <Text style={styles.title}>Recipe Name | 10 Mins</Text>
                          </View>
                        </TouchableHighlight>
                        <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegan</Text>
                           </View>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegie</Text>
                           </View>
                           <View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
                             <Text style={styles.upvotenum} >20</Text>
                             <Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
                             <Image style={styles.nombtn} source={require('image!nombtn')}></Image>
                            </View>
                        </View>
                      </LinearGradient>
                    </View>
                </Image>
            </View>
        </Swipeout>
        <Seperator/>
        <Swipeout right={list}>
            <View style={styles.container}>
                <Image source={{uri: 'http://m5.paperblog.com/i/37/370315/guest-blogger-vegan-richa-samosa-and-onion-bh-L-KmHfF4.jpeg'}} style={{width: window.width, height: window.width}}>
                  <View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
                    <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                      <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                        <Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
                        <Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
                      </View>
                    </View>
                    <LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
                        <TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
                          <View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
                            <Text style={styles.title}>Recipe Name | 10 Mins</Text>
                          </View>
                        </TouchableHighlight>
                        <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegan</Text>
                           </View>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegie</Text>
                           </View>
                           <View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
                             <Text style={styles.upvotenum} >20</Text>
                             <Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
                             <Image style={styles.nombtn} source={require('image!nombtn')}></Image>
                            </View>
                        </View>
                      </LinearGradient>
                    </View>
                </Image>
            </View>
        </Swipeout>
        <Seperator/>
        <Swipeout right={list}>
            <View style={styles.container}>
                <Image source={{uri: 'http://www.choosingraw.com/wp-content/uploads/2014/09/IMG_8328.jpg'}} style={{width: window.width, height: window.width}}>
                  <View style={{backgroundColor: 'transparent', marginBottom: 100,}}>
                    <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                      <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                        <Image source={{uri: 'http://cookieandkate.com/images/2014/02/kate-600.jpg'}} style={styles.profilebubble}/>
                        <Image source={{uri: 'http://www.thetimes.co.uk/tto/multimedia/archive/00851/82ef9ae8-ae34-11e4-_851122b.jpg'}} style={styles.profilebubble}/>
                      </View>
                    </View>
                    <LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
                        <TouchableHighlight onPress={Actions.recipedetails} underlayColor='transparent'>
                          <View style={{backgroundColor:'transparent', height: window.width, marginTop:-20}}>
                            <Text style={styles.title}>Recipe Name | 10 Mins</Text>
                          </View>
                        </TouchableHighlight>
                        <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: -75}}>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegan</Text>
                           </View>
                           <View style={styles.dietbuble}>
                              <Text style={styles.dietText}>Vegie</Text>
                           </View>
                           <View style={{flex: 1, flexDirection: 'row', marginLeft: window.width/3, backgroundColor: 'transparent'}}>
                             <Text style={styles.upvotenum} >20</Text>
                             <Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
                             <Image style={styles.nombtn} source={require('image!nombtn')}></Image>
                            </View>
                        </View>
                      </LinearGradient>
                    </View>
                </Image>
            </View>
        </Swipeout>
        <Seperator/>
      </ScrollView>
    )
  }
};


module.exports = Recipes;

Och detta är vyen för receptdetaljer:

'use strict';

var React = require('react-native');
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
var LinearGradient = require('react-native-linear-gradient');
var Tabbar = require('react-native-tabbar');
var Item = Tabbar.Item;
var {
  StyleSheet,
  View,
  Text,
  Component, 
  Image, 
  ScrollView, 
  TouchableHighlight,
} = React;

var styles = StyleSheet.create({
  description: {
    fontSize: 20,
    textAlign: 'center',
    color: '#FFFFFF'
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'transparent',
  }, 
  venue_image: {
    width: window.width, 
    height: window.height/4, 
    flex: 1, 
  }, 
  linearGradient: {
    flex: 1,
    paddingLeft: 15,
    paddingRight: 15,
    opacity: 0.9,
    height: window.height/3.7, 
  },
  title: {
    textAlign:'left', 
    fontSize: 15, 
    color: 'white', 
    fontFamily: 'Avenir Next', 
    fontWeight: '500',
  },
  nombtn: {
    height: 30,
    width: 30,
    marginBottom: 5,
  }, 
  arrow: {
    height: 15,
    width: 15,
    marginRight: 20,
    marginTop: 5,
  }, 
  upvotenum: {
    marginRight: 5, 
    fontSize: 20, 
    fontWeight: "600",
    color: 'white',
    fontFamily: 'Avenir Next'
  }, 
  dietbuble: {
    backgroundColor:'transparent', 
    height:20, 
    width:60, 
    borderRadius: 10, 
    backgroundColor:'#49B64D',
    marginRight:5,
  },
  submenutext: {
    fontFamily: 'Avenir Next',
    fontSize: 15,
    fontWeight: '600', 
    color: 'white',
    alignSelf: 'center', 
    marginTop: 10,
  }, 
  undernum: {
    fontFamily: 'Avenir Next',
    fontSize: 30,
    fontWeight: '400', 
    color: 'white',
    alignSelf: 'center', 
  }, 
  units: {
    fontFamily: 'Avenir Next',
    fontSize: 10,
    color: 'white',
    alignSelf: 'center',
  }
});

class VenueDetails extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedTab: 'ingredients',
    };
  }

  _Directions() {
    this.setState({selectedTab: 'directions'});
    console.log(this.state.selectedTab);
  }

  _Nutrition() {
     this.setState({selectedTab: 'nutrition'});
     console.log(this.state.selectedTab);
  }

  _Ingredients() {
    this.setState({selectedTab: 'ingredients'});
    console.log(this.state.selectedTab);
  }

  makeBackground(btn){
    var featurebox = {
     flex: 1,
     height: window.width/4,
     width: window.width/3,
     alignItems: 'center',
     justifyContent: 'center',
    }
    if(btn === 0 || btn === 2){
      featurebox.backgroundColor = '#49B64D';
    } else if (btn === 1){
      featurebox.backgroundColor = '#585858';
    } 
    return featurebox;
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={styles.container}>
            <Image source={{uri: 'http://i.huffpost.com/gadgets/slideshows/404432/slide_404432_5031844_free.jpg'}} style={styles.venue_image}>
              <LinearGradient colors={['transparent', 'transparent', '#1C1C1C']} style={styles.linearGradient}>
                <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent', marginTop: window.height/4.3}}>
                   <View style={{backgroundColor:'transparent', marginRight: window.width/4, marginLeft: 10}}>
                      <Text style={styles.title}>Recipe Name | 10 Mins</Text>
                   </View>
                   <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
                     <Text style={styles.upvotenum} >20</Text>
                     <Image style={styles.arrow} source={require('image!upvotearrow')}></Image>
                     <Image style={styles.nombtn} source={require('image!nombtn')}></Image>
                    </View>
                </View>
               </LinearGradient>
            </Image>
        </View>
        <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'transparent'}}>
            <TouchableHighlight 
              onPress={this._Ingredients.bind(this)}
              style={this.makeBackground(0)}
              underlayColor='transparent'>
              <View>
                <Text style={styles.submenutext}>Ingredients</Text>
                <Text style={styles.undernum}>5</Text>
                <Text style={styles.units}>Count</Text>
              </View>
            </TouchableHighlight>
            <TouchableHighlight 
               onPress={this._Nutrition.bind(this)}
               style={this.makeBackground(1)}
               underlayColor='transparent'>
              <View>
                <Text style={styles.submenutext}>Nutrition</Text>
                <Text style={styles.undernum}>200</Text>
                <Text style={styles.units}>Sugars</Text>
              </View>
            </TouchableHighlight>
            <TouchableHighlight 
              onPress={this._Directions.bind(this)}
              style={this.makeBackground(2)}
              underlayColor='transparent'>
              <View>
                <Text style={styles.submenutext}>Directions</Text>
                <Text style={styles.undernum}>10</Text>
                <Text style={styles.units}>Hours</Text>
              </View>
            </TouchableHighlight>
        </View>
        <ScrollView>
        </ScrollView>
      </View>
    );
  }
}

module.exports = VenueDetails;

För närvarande ser allt detta ut så här:

Svar #1

Vad jag skulle göra är att skapa en array med objekt där varje objekt representerar de olika vyerna/komponenterna i din footer-slider-grej. Sedan, ha en egenskap i ditt state som är den aktiva fliken och när en användare klickar på en ny flik, uppdatera den aktiva fliken till att vara det nya indexet. Vad vi ska göra är, oavsett vilken flik som är aktiv, hämta den specifika komponenten som du hade i tabMap du gjorde ovan och rendera den. Koden kommer att se ut ungefär så här.

var tabMap = [
  {key: 0, icon: 'ion|ios-contact-outline', state: 'bio', asArray: false, Component: About},
  {key: 1, icon: 'ion|ios-paper', state: 'posts', asArray: true, Component: Posts},
  {key: 2, icon: 'ion|ios-people', state: 'friends', asArray: false, Component: Friends},
  {key: 3, icon: 'ion|ios-heart', state: 'activity', asArray: false, Component: Activity},
];

Så det representerar olika flikar i den nedre delen.

getInitialState(){
   return {
      activeTab: 0
   }
}

Det där är mitt initiala tillstånd som kommer att hålla reda på vilken flik jag är på.

Sedan i min renderingsmetod hämtar jag komponenten för den nuvarande aktiva fliken,

var BodyComponent = tabMap[this.state.activeTabIndex].Component;

Nu när jag har komponenten kan jag enkelt rendera BodyComponent och skicka in vilken data jag vill.

 <BodyComponent
    header={tabMap[this.state.activeTabIndex].header}
    authedUser={this.props.authedUser}
    isGuest={this.props.isGuest}
    userToRender={this.state.userToRender}
    data={this.state[tabMap[this.state.activeTabIndex].state]} />

Svar #2

Det var en saknad funktion i react-native-router-flux (att byta mellan 'flikar' inom en behållare) och jag har lagt till den nyligen, vänligen kontrollera senaste versionen.

Du behöver använda Container-elementet och definiera dina rutter inuti det. Du måste också definiera TabBar-implementeringen att använda med det containern (kolla exempel med dess TabBarFlux)