infernojs / inferno

:fire: An extremely fast, React-like JavaScript library for building modern user interfaces
https://infernojs.org
MIT License
16.09k stars 634 forks source link

inferno-route url params variable is undefined #317

Closed Yotooon closed 8 years ago

Yotooon commented 8 years ago

Hello, I'm quite new to Inferno and I love it so far but I've hit a wall with the routes component. I'm trying to pass an argument in the URL but it doesn't seem to work properly for me. Here's my code:

const Router = InfernoRouter.Router;
const Route = InfernoRouter.Route;
const Link = InfernoRouter.Link;
const browserHistory = InfernoRouter.browserHistory;

// Main App
class App extends InfernoComponent {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <h3>Menu</h3>
                <ul className="menu">
                    <li><Link to={'/'}>Home</Link></li>
                    <li><Link to={'/portfolio'}>Portfolio</Link></li>
                    <li><Link to={'/portfolio/websites'}>Portfolio - websites</Link></li>
                    <li><Link to={'/nah'}>Blank</Link></li>
                </ul>
                <h4>Section</h4>
                {this.props.children}
            </div>
        )
    }
}

const Home = () => <div>home sweet home...</div>

const PortfolioHome = () => (
    <div>portfolio home</div>
);

const PortfolioSection = ({params}) => (
    <div>portfolio section: {params.test}</div>
);

const NotFound = () => <div>Not Found...</div>

InfernoDOM.render((
    <Router history={browserHistory} component={App} hashbang="true">
        <Route path={'/'} component={Home}/>
        <Route path={'/portfolio'} component={PortfolioHome}/>
        <Route path={'/portfolio/:test'} component={PortfolioSection}/>
        <Route path={'*'} component={NotFound}/>
    </Router>
), 
document.getElementById('app'));

In the PortfolioSection the params variable is always undefined with the above code, but when I remove the component={App} from the <Router... the params variable is no longer undefined and i can access {params.test}. I've tried many combinations of the router/route but cannot get it to work. Am I missing something?

trueadm commented 8 years ago

@TenSoon App should have access to the params in props, so you can pass that down along with the children. So you could try this:

class App extends InfernoComponent {
    constructor(props) {
        super(props);
    }

    render() {
        const children = Object.assign({}, this.props.children, { 
           attrs: { params: this.props.params } 
        });
        return (
            <div>
                <h3>Menu</h3>
                <ul className="menu">
                    <li><Link to={'/'}>Home</Link></li>
                    <li><Link to={'/portfolio'}>Portfolio</Link></li>
                    <li><Link to={'/portfolio/websites'}>Portfolio - websites</Link></li>
                    <li><Link to={'/nah'}>Blank</Link></li>
                </ul>
                <h4>Section</h4>
                { children }
            </div>
        )
    }
}

Does this work for you?

Yotooon commented 8 years ago

@trueadm Unfortunately no. It spits out an error: inferno-dom.js:807 Uncaught TypeError: Component is not a function

trueadm commented 8 years ago

@TenSoon Ah yes, sorry I was I forgot that the children were a VNode. I'll add a new pacakge called inferno-clone-element tonight that will replicate React.cloneElement that will help here. I've updated the example above to have a workable fix for now (that should work as a clone replacement for now).

trueadm commented 8 years ago

Inferno.cloneVNode into development for Inferno 1.0 rather than 0.7. 0.8 development is being skipped from now on in favour of 1.0.

pearofducks commented 8 years ago

Just a heads up, from that change to children, I now get:

inferno-dom.js:510 - Uncaught Error: Inferno Error: invalid object "object" passed to mount()

(this is against the following versions):

    "inferno": "^0.7.27",
    "inferno-component": "^0.7.27",
    "inferno-dom": "^0.7.27",
    "inferno-router": "^0.7.27",
trueadm commented 8 years ago

@pearofducks Can you paste in the code you are using and let me know what version you are using?

It might be an idea to use Inferno 1.0-alpha8, which has Inferno.cloneVNode. You can install 1.0alpha8 via NPM: npm i --save inferno@alpha8 (same for inferno-dom, inferno-router etc).

pearofducks commented 8 years ago

@trueadm

I tried upgrading everything inferno related to latest, I got another set of errors (IIRC related to blueprint once I had upgraded the babel plugin as well)

components:

import Inferno from 'inferno';
import Component from 'inferno-component';
import { observable, computed, action } from 'mobx';
import { observer } from 'mobx-observer';
import marked from 'marked';
import { recipeStore } from './stores';
import { Link } from 'inferno-router';

@observer
export class Layout extends Component {
  componentDidMount() { recipeStore.loadRecipes(); }
  constructor(props) { super(props); }
  render() {
    const children = Object.assign({}, this.props.children, {
      attrs: { params: this.props.params }
    });
    return (
      <div>
        <div className="header">
          <h1>
            { recipeStore.currentRecipeSlug
              ? <Link to="/">foodProcessor</Link>
              : "foodProcessor"
            }
          </h1>
          { recipeStore.currentRecipe ? <h2 className="recipe-name">{recipeStore.currentRecipe.name}</h2> : "" }
        </div>
        <div className="allChildContent"> { children } </div>
      </div>
    );
  }
}

@observer
export class RecipeList extends Component {
  componentDidMount() { recipeStore.currentRecipeSlug = null; }
  render() {
    return (
      <div className="recipeListBlock">
        <ul>
        { recipeStore.recipes.map((recipe,i) =>
            <li key={i}>
              <h2>
                <Link to={`/${recipe.slug()}`}> {recipe.name} </Link>
              </h2>
            </li>
         )}
        </ul>
      </div>
    );
  }
}

index:

import Inferno from 'inferno';
import { render } from 'inferno-dom';
import { Router, Route, browserHistory } from 'inferno-router';
import { Layout, Recipe, RecipeList } from './components';

const routes = (
  <Router component={ Layout } history={ browserHistory }>
    <Route path="/" component={ RecipeList } />
    <Route path="/:name" component={ Recipe }/>
  </Router>
);
pearofducks commented 8 years ago

With these upgraded, but old babel:

    "inferno": "1.0.0-alpha8",
    "inferno-component": "1.0.0-alpha8",
    "inferno-dom": "1.0.0-alpha8",
    "inferno-router": "1.0.0-alpha8",

I get components.jsx:7 - Uncaught TypeError: _inferno2.default.createBlueprint is not a function

(line 7 is import { Link } from 'inferno-router';)

If I upgrade the babel package to alpha5, then I get:

inferno-dom.js:91 - Uncaught Error: Inferno Error: bad input argument called on mount(). Input argument may need normalising.

trueadm commented 8 years ago

@pearofducks if you use babel-plugin-inferno@alpha8 that should help with some of those issues.

pearofducks commented 8 years ago

That helped. It seems there some new incompatibility between <Link> and mobx reactions.

I'm using mobx-observer, because I couldn't get mobx-inferno working with alpha8.

This works:

@observer
export class RecipeList extends Component {
  ...
                <a href={`/${recipe.slug()}`}> {recipe.name} </a>
  ...   
}

This does not:

@observer
export class RecipeList extends Component {
  ...   
                <Link to={`/${recipe.slug()}`}> {recipe.name} </Link>
  ...   
}
trueadm commented 8 years ago

Ah, third party libraries will need updating to support 1.0. 1.0 has a completely different internal API from 0.7.

On 15 Sep 2016, at 11:56, Dave Honneffer notifications@github.com wrote:

That helped. It seems there some new incompatibility between and mobx reactions.

I'm using mobx-observer, because I couldn't get mobx-inferno working with alpha8.

This works:

@observer export class RecipeList extends Component { ... <a href={/${recipe.slug()}}> {recipe.name} ...
} This does not:

@observer export class RecipeList extends Component { ...
<Link to={/${recipe.slug()}}> {recipe.name} ...
} — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

pearofducks commented 8 years ago

@trueadm - just a heads up, inferno-create-class 1.0.0-alpha8 is missing from npm

trueadm commented 8 years ago

@pearofducks published it. I'm going to close this issue now as the original issue has been added to Inferno 1.0.