pors / reactionic

React Ionic: We are looking for a new maintainer!

Home Page:http://reactionic.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ionSnapper is undefined

keiranvv opened this issue · comments

Hi,

I'm trying to use the IonSideNav set of components, however, I'm getting the above error when I try to use it.

Here's an example of the code from my App component (let me know if I need to include anything else):

    <IonBody location={this.props.location} >
        <IonSideMenuContainer>
          <IonSideMenus>
            <IonSideMenu>...</IonSideMenu>
          </IonSideMenus>
          <IonSideMenuContent>
              <IonNavBar customClasses="bar-light"
                 title="My App"
                 leftButton={this.navButton()} />
               <IonNavView>
                <IonView>
                  {this.props.children}
                </IonView>
              </IonNavView>
          </IonSideMenuContent>
        </IonSideMenuContainer>
      </IonBody>

Are you using contextTypes in your App component.
You can see an example of a component using it.

https://github.com/reactionic/reactionic/blob/master/src/components/ionBody.js

What @gabrielseco says. Also, have a look at this page to see how to control the sidemenus with clicks next to dragging: https://github.com/reactionic/reactionic-kitchensink/blob/master/app/client/imports/components/layouts/main.jsx

@gabrielseco do you mean the following?

contextTypes: {
    ionSnapper: React.PropTypes.object
  },

If so, then yes I have added it.

@pors That is indeed the example I've followed :)

@keiranvv yes, i meant that.

Could you show us the entire component to see where the problem is

Sure thing:

App.jsx:

import React, { Component } from 'react'
import { IonBody, IonIcon, IonNavBar, IonNavView, IonSideMenuContainer, IonSideMenuContent, IonSideMenu, IonSideMenus, IonView } from 'reactionic'
import SideMenu from './sidemenu'

export default App = React.createClass({
  contextTypes: {
    ionSnapper: React.PropTypes.object
  },

  render() {
    return (
      <IonBody location={this.props.location}>
        <IonSideMenuContainer>
          <IonSideMenus>
            {this.sideMenu()}
          </IonSideMenus>
          <IonSideMenuContent>
              <IonNavBar customClasses="bar-light"
                 title="Oviation"
                 leftButton={this.navButton()} />
               <IonNavView>
                <IonView>
                  {this.props.children}
                </IonView>
              </IonNavView>
          </IonSideMenuContent>
        </IonSideMenuContainer>
      </IonBody>
    )
  },

  navButton() {
    if (Meteor.userId() === null) return

    return (
      <a onClick={() => { this.context.ionSnapper.toggle('left') }} className="button button-icon icon ion-navicon"></a>
    )
  },

  sideMenu() {
    if (Meteor.userId() === null) return
    return (
      <IonSideMenus>
        <SideMenu />
      </IonSideMenus>
    )
  }
})

SideMenu.jsx

import React from 'react'
import { IonSideMenu } from 'reactionic'

export default SideMenu = React.createClass({
  contextTypes: {
    ionSnapper: React.PropTypes.object
  },

  render() {
    return (
      <IonSideMenu customClasses="side-menu">
        <div className="bar bar-header bar-stable">
          <h1 className="title">Left Menu</h1>
        </div>
        <div className="content has-header side-menu">
          <div className="list">
          </div>
        </div>
      </IonSideMenu>
    )
  }
})

Well, I kinda detected the problem.

The ionBody component sets the snapper to null.

You can see the ionSnapper state is null. line 44.

https://github.com/reactionic/reactionic/blob/master/src/components/ionBody.js

Well if in your App.jsx remove the ionBody, the ionSnapper works.

So in the https://github.com/reactionic/reactionic-kitchensink/blob/master/app/client/router.jsx.

Import your App.jsx without the IonBody component in the router.jsx.

I would change the name because there's an App component with the IonBody component.

let mainRoute = (


{pageRoutes}

);

Tell me if it is this what you needed

removing the ionBody doesn't seem to work. I'm in the process of copying the kitchen sink setup line by line, but it still doesn't seem to be working.

I'll carry on and update if i resolve it.

this.context.ionSnapper is still null.

Can you see anything wrong with my router.jsx?

Router.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import { IndexRoute, Router, Route, browserHistory } from 'react-router'
import App from '../imports/ui/app/app'
import Main from '../imports/ui/app/main'
import Forms from '../imports/ui/forms/forms'
import FormEdit from '../imports/ui/forms/form_edit'

const main = () => {
  let mainRoute = (
    <Route component={Main}>
      <IndexRoute component={Forms} />
      <Route path='/forms/new' component={FormEdit} />
    </Route>
  );

  var routes = (
    <Route path="/" component={App}>
      { mainRoute }
    </Route>
  );

  ReactDOM.render(<Router history={browserHistory}>{routes}</Router>, document.getElementById('root')) ;
}

Meteor.startup(main)

App.jsx

import { IonBody } from 'reactionic'
import React from 'react'
import { getPlatform } from '../utils/helper'

export default App = React.createClass({
  getInitialState() {
    return {platformOverride: this.props.location.query.platformOverride};
  },

  componentWillReceiveProps: function(newProps) {
    var newPlatformOverride = newProps.location.query.platformOverride;
    if (newPlatformOverride) {
      if (newPlatformOverride !== this.state.platformOverride) {
        this.setState({platformOverride: newPlatformOverride});
      }
    }
  },

  render() {
    var platform = getPlatform(this.state.platformOverride);
    return (
      <IonBody platform={platform} location={this.props.location} >
        { React.cloneElement(this.props.children) }
      </IonBody>
    )
  }
})

If you can't see anything wrong then I'm probably going to have to write my own slide out menu, as I can't see any other clear reason that this isn't working.

The App.jsx is the same that I have.

In the router.jsx my Main Component load in mainRoute, probably is different.

Look at this component.

https://github.com/gabrielseco/snapperExample/blob/master/app/client/imports/components/snapper.jsx

I'll show you a capture working with it.
captura de pantalla 2016-05-10 a las 22 16 15

Ok, well I copied that component as is, and it still does the same thing. I'm going to have to write my own slide menu component for this app.

Thanks so much for all your help, really appreciate it.

So, I potentially found the bug I think?

I originally added the package using meteor's command, ie. meteor npm i -S reactionic

I tried removing the package: meteor npm uninstall -S reactionic and then re-adding with npm i -S reactionic without the meteor keyword, and it worked!

Glad you solved it.

Edit 3 -- Solution:

If you are new to React Context, there a few things to note. This package keeps track of the UI state in the highest level context, at the very top level of the app. Your app should be designed (forcefully) this way:

<YourAppWrapper /*wraps your app with ionic functionality*/>
  <IonBody /*this tracks the UI state via React's context*/>
    <YourApp /*anything in your app under here can access the UI state via the context*/>
//closing tags

Every component class you export which falls under the IonBody can access the UI/cosmetic state of the app, and has the ability to manipulate that state only if you specify Component.contextTypes, which works analogously to Component.propTypes. [I think] manipulating the state will re-diff your entire app, because your entire app sits inside of IonBody. Is this performant? That's another conversation.

Things to check:

  1. Specify the right contextTypes in each component you build, if you want to interface with ionic's UI/cosmetic capabilities.
  2. Do not use ionSnapper directly. For some reason, the IonBody state change is not triggering a child context change, leaving the context's ionSnapper as null. This must be a problem with context or the design of IonBody, or IonBody's integration of context may be outdated.
  3. Use 'ionGetSnapper' instead, which is guaranteed to reference the current state of the IonBody's snapper.
//component that needs ionSnapper.
toggleSnapper(){
  this.context.ionGetSnapper().toggle('left');
}
render(){
  return (
    //jsx, uses this.toggleSnapper onClick somewhere.
  )
}

@keiranvv that solution did not work for me, the app still makes it null.
I am curious why this package uses react's context, when the context feature is highly experimental. Inevitable changes in this feature would certainly break this package. This package claims to be "production ready", which I think might be false advertising. That said, I do think this package is awesome.

Edit 1:

this.context.ionSetSnapper(snapper);

is being called in the sideMenuContainer file. For some reason, the ionBody is not setting the context properly. I am guessing this is because of the problem above -- do not use context, it will change and break your package! I will look more into it.

Edit 2:

this.setState({ionSnapper: snapper}) 

is being called exactly once, and snapper !== undefined. For some reason, the change in state is not updating the context, OR the context updates are not propagating to children. Will keep posted.

Context is not highly experimental as far as I know. Even react-router is
using it.

On Saturday, May 28, 2016, Streemo notifications@github.com wrote:

@keiranvv https://github.com/keiranvv that solution did not work for
me, the app still makes it null.
I am curious why this package uses react's context, when the context
feature is highly experimental. This package claims to be "production
ready", which I think might be false advertising.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#41 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/ABB0MAEkTTf14LyeqFe9xd7iCHe2QlKKks5qF3OmgaJpZM4IbQSd
.

https://facebook.github.io/react/docs/context.html

This advises not to use context. Is that only for React 1? Is there a newer version of React in which context is stable?
Thanks.

Yes context is bad practice for applications but very handy for libraries
where you don't want to make assumptions for the developer.

On Saturday, May 28, 2016, Streemo notifications@github.com wrote:

https://facebook.github.io/react/docs/context.html

This advises not to use context. Is that only for React 1? Is there a
newer version of React in which context is stable?
Thanks.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#41 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/ABB0MLXnf-RdwBMZTZe8WxxvWyK7y1YCks5qF4KRgaJpZM4IbQSd
.

I'm still having issues getting null for snapper.