mcnamee / react-native-starter-kit

:rocket: A React Native boilerplate app to get you up and running very, very quickly :rocket:
MIT License
3.34k stars 863 forks source link

Referring to only 1 SideMenu Throughout Code #2

Closed robtg4 closed 8 years ago

robtg4 commented 8 years ago

I seem to be having some difficulty with requiring only one side menu per app instead of having the same side menu implemented on every page that the menu can navigate to - much like keeping one tabbar per app where you can navigate to the different tab pages

right now, my home.js component - the first page to have the side menu, looks like this (i took the toggle implementation you used to make the menu work with MenuButton):

var React = require('react-native');
var {
    View, 
    Image,
    StyleSheet,
    Text, 
    ListView, 
    TouchableHighlight, 
    AsyncStorage, 
} = React;

//additional libraries
var Parse = require('parse/react-native');
var EventEmitter = require('EventEmitter');
var Spinner = require('react-native-spinkit');
var SideMenu = require('react-native-side-menu');
var Subscribable = require('Subscribable');

//dynamic component references + libraries 
var ArticlePreview = require('./exp_base_components/article-preview');
var Api = require('../utils/api');
var FeedStore = require('../stores/feed-store');
var ArticleDetails = require('./exp_base_components/article-details');
var Menu = require('./menu');
var MenuButton = require('../common/menuButton');

//dimensions
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');

module.exports = React.createClass({ 
    //mixins are for menu functionality taken from 
    //here: https://github.com/mcnamee/react-native-starter-app
    mixins: [Subscribable.Mixin],
    componentWillMount: function() {
        this.eventEmitter = new EventEmitter();
        Parse.User.currentAsync()
            .then((user) => { this.setState({user: user}); })
    },  
    //on first login (and all new logins)
    //need to pull onboarding keywords that indicate user interests
    //so that we can pull the appropiate feeds 
    componentDidMount: function() {
        //console.log(this.state.user);
        var personalFeed = null; 
        var Onboarding = Parse.Object.extend("Onboarding");
        var query = new Parse.Query(Onboarding);
        query.equalTo("userObjectId", Parse.User.current());
        var that = this;
        query.find({
          success: function(result) {
            console.log("Successfully retrieved " + result.length + " users!");
            var object = result[0];
            console.log(object.id);
            // Do something with the returned Parse.Object values
            console.log(object.get('interests'));
            that.fetchData(object.get('interests'));
          },
          error: function(error) {
            console.log("Error: " + error.code + " " + error.message);
          }
        });

    },
    //states of this components 
    getInitialState: function() {
        return {
            user: null, 
            personalFeed: null, 
            touchToClose: true,
            disableGestures: false,
            isLoaded: false, 
            dataSource: new ListView.DataSource({
               rowHasChanged: (row1, row2) => row1 !== row2,
            }), 
        }
    },
    //part of menu button functionality 
    navigate: function(title, link) {
      this.refs.rootSidebarMenu.closeMenu();

      this.refs.rootNavigator.replace({
        title: title,
        component: link,
      });
    },
    //gettign data for rss feed based on user interests 
    fetchData: function(personalFeed) {
        var that = this; 
        FeedStore.getArticles(personalFeed)
            .then((data) => {
                var entries = data; 
                that.setState({
                    dataSource : that.state.dataSource.cloneWithRows(entries),
                    isLoaded   : true, 
                });
            }).done();
    }, 
    //rendering component 
    render: function() {

        if (!this.state.isLoaded) {
            return this.renderLoadingView();
        }
        return <SideMenu 
                    menu={<Menu events={this.eventEmitter} navigate={this.navigate} />}
                    touchToClose={this.state.touchToClose}
                    disableGestures={this.state.disableGestures}
                    toleranceX={0}
                    edgeHitWidth={window.width/5}
                    openMenuOffset={window.width/5}>
                <View style={styles.container}>
                    {this.renderListView()}
                </View>
                <MenuButton 
                    selected={this.state.enoughSelections}
                    source={require('../img/menu-btn.png')}
                    resize={'contain'}
                    onPress={this.onMenuPress} />
            </SideMenu>
    },
    //menu press function 
    onMenuPress: function() {
        this.eventEmitter.emit('toggleMenu');
    }, 
    //loading render
    renderLoadingView: function() {
        return (
            <View style={styles.container}>
                <Spinner style={styles.spinner} isVisible={!this.state.isLoaded} size={50} type={'Arc'} color={'#FF0000'}/>
            </View>
        );
    }, 
    //rendering list view
    renderListView: function() {
        return (
                <ListView
                    dataSource = {this.state.dataSource}
                    initialListSize = {5}
                    pageSize={5}
                    renderRow  = {this.renderEntry} />
        );
    }, 
    //rendering rows within list view
    renderEntry: function(entry) {

        if (typeof entry.mediaGroups === 'undefined')
        {
            return (
                <ArticlePreview
                    category={entry.categories[0]}
                    key={entry.title}
                    heartText={'2.9k'}
                    categoryPress={this.onCategoryDetailsPress}
                    selected={false}
                    source={require('../img/stock_image.png')}
                    text={entry.title.toLowerCase().replace('&nbsp;','')}
                    onPress={() => this.onArticleDetailsPress(entry)} />
            );
        } else 
        { 
            var url = entry.mediaGroups[0].contents[0].url; 
            if (url.indexOf('w=150') > -1)
            {
                url.replace("w=150", "w=500");
            }
            var catsource = entry.categories[0]; 
            if (typeof catsource == "undefined")
            {
                catsource = "News";
            }
            return (
                <ArticlePreview
                    category={catsource}
                    key={entry.title}
                    heartText={'2.9k'}
                    categoryPress={this.onCategoryDetailsPress}
                    selected={false}
                    source={{uri: url }}
                    text={entry.title.toLowerCase().replace('&nbsp;','')}
                    onPress={() => this.onArticleDetailsPress(entry)} />
            );
        }

    },
    //pressing category button to go to feed of that category 
    onCategoryDetailsPress: function() {
        //forward to sytled web view of categorical article feed
        console.log("onCategoryDetailsPress"); 
    }, 
    //press to see article's details 
    onArticleDetailsPress: function(entry) {
        //forward to sytled web view of article details given link
        console.log("onArticleDetailsPress"); 
        console.log(entry);

        //asynchronously store entry

        //pushing to new component
        this.props.navigator.push({
            name: 'articledetails',
            passProps: {entry: entry},
        });
    }, 
    /*
    onChange: function(event, articles) {
        this.setState({articles: articles}); //trigers re-render of component
    }
    */

});

The problem is that i can navigate to the other pages because the Menu component referenced in the SideMenu does not have Navigator as a part of it - so pushing to the next page is meaningless to it. Is there a better way to implement this? I can give you access to the repo if needed.

robtg4 commented 8 years ago

http://stackoverflow.com/questions/34417144/create-a-side-menu-home-page-with-react-native-navbar-react-native-router-flux

mcnamee commented 8 years ago

Hi there @robtg4 Take a look at the structure of the starter app, where everything routes/pushes/replaces through the same navigator, and this navigators sits on the same level as the SideMenu. Looking at your code snippet, you have the SideMenu inside the navigator - is that correct? If so, it's a different structure to the starter app.

Following the structure of the starter app should guide you to be able to have a single SideMenu through the App.

robtg4 commented 8 years ago

I think the problem that I'm having is that I can't seem to be able to create routes before the sidemenu. Like a login ans signup page that goes to the side menu frame after parse authentication. The reason that I believe this happens is because given the way the sidemenu app is set up, the navigator routes become nested if you put screens before the side menu app screens. What are your thoughts?

Everytime I route to the side menu screens by adding a sign in screen, it gives me an invariant navigator error.

mcnamee commented 8 years ago

Hi @robtg4

Yeah ok - the starter app does assume you've got a single navigator. Unfortunately I'm not familiar enough with the other frameworks you're using, to give guidance on combining them with this one.

I did however do a similar thing with the starter app framework recently, where the initial route/splash screen simply covered (over the top of) the navbar, and the user could click login/signup. From there it operated as normal, where the signup or login screen was pushed to the stack, and clicking back would go back to the splash screen. I also had a 'skip login' button which just replaced the screen to another.

robtg4 commented 8 years ago

Would it be possible to put that as a repo up - minus any sensitive info? I just can't seem to get the build with screens before the side menu lol, it's halted my whole build I think your repo is the only complete side menu out there On Dec 27, 2015 3:21 AM, "Matt Mcnamee" notifications@github.com wrote:

Hi @robtg4 https://github.com/robtg4

Yeah ok - the starter app does assume you've got a single navigator. Unfortunately I'm not familiar enough with the other frameworks you're using, to give guidance on combining them with this one.

I did however do a similar thing with the starter app framework recently, where the initial route/splash screen simply covered (over the top of) the navbar, and the user could click login/signup. From there it operated as normal, where the signup or login screen was pushed to the stack, and clicking back would go back to the splash screen. I also had a 'skip login' button which just replaced the screen to another.

— Reply to this email directly or view it on GitHub https://github.com/mcnamee/react-native-starter-app/issues/2#issuecomment-167392615 .

mcnamee commented 8 years ago

Sorry it's not really possible for this client.

It's really just a matter of styling a with margin top of 'negative the height of the navbar', height of the screen and background color as white. This view then sits over everything, so you can put login/signup buttons inside it.