React-Router 1.0.0RC1 - 将状态作为属性传递给子路由

React-Router 1.0.0RC1 - Passing state as properties to child routes

我正在 Alex Bank's "Building a Polling App with Socket IO and React.js" (Lynda.com) 工作,但我正在尝试将其升级到 react-router 1.0.0-RC1。

Solution below, just skip all this

请不要给我看文档,它对我不起作用,我想我一定是太厚了,看不懂文档的"pithiness"。

我有一个带有 3 个子路径的主应用程序,(观众、演讲者和董事会)。

到目前为止我的代码:

APP.js

import React, { Component } from 'react';
import io from 'socket.io-client';
import Header from './parts/Header';
import Routes from '../router/routes';
import { createHistory, useBasename } from 'history';

const history = useBasename(createHistory)({
  basename: '/'
});

export default class APP extends Component {

  constructor() {
    super();
    this.state = ({
      status: 'disconnected',
      title: ''
    });
  }

  componentWillMount() {
    this.socket = io('http://localhost:3000');
    this.socket.on('connect', this.connect.bind(this));
    this.socket.on('disconnect', this.disconnect.bind(this));
    this.socket.on('welcome', this.welcome.bind(this));
  }

 connect() {
    this.setState({status: 'connected'});
 }

 disconnect() {
    this.setState({status: 'disconnected'});
 }

 welcome(serverState) {
    this.setState({title: serverState.title});
 }

render() {
   return (
     <div>
       <Header title={ this.state.title } status={ this.state.status }/>
       { /* I WANT TO PASS THIS.STATE.STATUS TO CHILD ROUTES  */}
       <Routes history={ history } />
     </div>
    );
  }
}

Routes.js

import React, { Component } from 'react';
import Route from 'react-router';
import APP from '../components/APP';
import Audience from '../components/Audience';
import Board from '../components/Board';
import Speaker from '../components/Speaker';
import NotFound from '../components/NotFound';


export default class Routes extends Component {
  constructor() {
    super();
  }

  render() {
    return (
      <Route history={ this.props.history } component={ APP }>
        <Route path="/" component={ Audience } />
        <Route path="audience" component={ Audience } />
        <Route path="board" component={ Board } />
        <Route path="speaker" component={ Speaker } />
        <Route path="*" component={ NotFound } />
      </Route>
    );
  }
}

Audience.js

import React, { Component } from 'react';

export default class Audience extends Component {

 constructor() {
   super();
 }


 render() {
   return (
     <div>
      Audience - STUCK HERE!! - How to pass APP's this.state.status as a prop????        
     </div>
   );
 }

}

尽管应用程序运行,并且我已阅读文档,但我仍然无法将应用程序的 this.state.status 作为 属性 传递给受众应用程序。

我已经为此工作了 2 天,但无济于事,而且越来越令人沮丧。 TGIF.

Desired Result:

When a browser is opened to localhost:3000, the default page (Audience.js), should read as:

 Untitled Presentation - connected

 Audience - connected

I cannot get the status of connected passed to the Audience component so the word 'connected' is not showing up next to Audience. I am connected as evidenced by Header's "Untitled Presentation - connected"

有人可以帮我吗。

非常感谢!

在您的 APP 组件中,您需要包含以下内容:

{React.cloneElement(this.props.children, {status: this.state.status })}

然后在您的 audience 组件中,您将可以使用 this.props.status

编辑:

我刚刚注意到您有循环依赖。我建议摆脱它,以便只在一个方向上依赖:

routes.js --> app.js --> audience.js

看看这个 example。这可以通过提取两个 React 类:

分成三个文件
  1. main.js 这会呈现路线
  2. App.js 这会呈现应用程序并包含子路由
  3. Taco.js 这呈现了炸玉米饼。

这可以表示如下:

    main.js --> App.js --> Taco.js

SOLUTION:

正如 Clarkie 所提到的,我确实有循环依赖,因为我正在遵循使用 react-router 0.13 并将 APP 作为入口点的旧设置。

这个问题的大部分帮助来自iam4x/isomorphic-flux-boilerplate

It is 'sad' detailed assistance could not have been found directly from the react-router documentation.


我现在的新入口点是:

Index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Router from 'react-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';

  const routerProps = {
    routes: require('./router/routes'),
    history: createBrowserHistory(),
    createElement: (component, props) => {
      return React.createElement(component, { ...props});
    }
  };

  ReactDOM.render(
    React.createElement(Router, { ...routerProps }),
    document.getElementById('root')
  );

Routes.js:

Note: I especially like how they did the routes, because I can see quite clearly how to turn this dynamic (w/ data from Db) for large apps.

import React from 'react';
import { Route } from 'react-router';
import { generateRoute } from '../utils/localized-routes';

export default (
  <Route component={ require('../components/APP') }>
    { generateRoute({
      paths: ['/', '/audience'],
      component: require('../components/Audience')
    }) }
    { generateRoute({
      paths: ['/speaker'],
      component: require('../components/Speaker')
    }) }
    { generateRoute({
      paths: ['board'],
      component: require('../components/Board')
    }) }
    <Route path="*" component={ require('../components/NotFound') } />
  </Route>
);

本地化-routes.js:

import React from 'react';
import { Route } from 'react-router';

export function generateRoute({ paths, component }) {
  return paths.map(function(path) {
    const props = { key: path, path, component };
    // Static `onEnter` is defined on
    // component, we should pass it to route props
    if (component.onEnter) props.onEnter = component.onEnter;
    return <Route {...props} />;
  });
}

// SWEET!!! Nice touch.
export function replaceParams(route, params) {
  let parsedRoute = route.trim();
  Object.keys(params).forEach(function(paramKey) {
    const param = ':' + paramKey;
    const paramValue = params[paramKey];
    if (parsedRoute && parsedRoute.match(param)) {
      parsedRoute = parsedRoute.replace(param, paramValue);
    }
  });
  return parsedRoute;
}

APP.js:

import React, { Component, PropTypes } from 'react';
import io from 'socket.io-client';
import Header from './parts/Header';

export default class APP extends Component {
  static propTypes = {
    children: PropTypes.element
  }

  constructor(props, context) {
   super(props, context);
   this.state = ({
    status: 'disconnected',
    title: ''
  });
 }

 componentWillMount() {
  this.socket = io('http://localhost:3000');
  this.socket.on('connect', this.connect.bind(this));
  this.socket.on('disconnect', this.disconnect.bind(this));
  this.socket.on('welcome', this.welcome.bind(this));
}

 connect() {
   this.setState({ status: 'connected' });
}

 disconnect() {
   this.setState({ status: 'disconnected' });
}

 welcome(serverState) {
   this.setState({ title: serverState.title });
}

 renderChild = () =>
   React.cloneElement(this.props.children, { status: this.state.status });

 render() {
   return (
      <div>
         <Header title={ this.state.title } status={ this.state.status }/>
        { React.Children.map(this.props.children, this.renderChild) }
      </div>
    );
  }
}

Audience.js:

import React, { Component } from 'react';
import Display from './Display';

export default class Audience extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div>
       Audience - { this.props.status }
        <Display if={ this.props.status === 'connected' }>
          <h1>Join the session</h1>
        </Display>
      </div>
     );
   }
 }

Display.js:

import React, { Component } from 'react';

export default class Display extends Component {
  render() {
    return (
        <div>
        { this.props.if ? <div> { this.props.children } </div> : null }
        </div>
        );
    }
}

DESIRED RESULT: