denvned / isomorphic-relay-router

Adds server side rendering support to react-router-relay
BSD 2-Clause "Simplified" License
137 stars 26 forks source link

RelayContainer: Expected prop `viewer` to be supplied to `App`, but got `undefined` #52

Closed saltas888 closed 8 years ago

saltas888 commented 8 years ago

Hello, Im trying to run a simple app like the todo example but i get this

> RelayContainer: Expected prop viewer to be supplied to App, but got undefined

The strange thing is that from the server side i get the viewer property correctly:

...otherProps, viewer: { __dataID__: 'Vmlld2VyOjE=', id: 'Vmlld2VyOjE=', users: { __dataID__: 'client:14189082351_first(5)', edges: [Object] } }, ...moreProps

Here is My App Component:

import React from 'react'
import Relay from 'react-relay';

import get from 'lodash/get'
import last from 'lodash/last'
import merge from 'lodash/merge'
class App extends React.Component {
  render(){
    console.log('App props'+process.env.BROWSER,this.props)
    return (
      <div>
        <div>
          {get(this.props, 'viewer.id')}
        </div>
      </div>
    )
  }
}

export default Relay.createContainer(App, {
  fragments: {
    viewer: () => Relay.QL`
      fragment on Viewer {
        id,
        users(first: 5){
          edges{
            node{
              email,
              invite_token
            }
          }
        }
      }
    `,
  },
});

Here is the client-side render function:

const environment = new Relay.Environment();

  environment.injectNetworkLayer(new Relay.DefaultNetworkLayer('/graphql'));

  const data = JSON.parse(document.getElementById('preloadedData').textContent);

  IsomorphicRelay.injectPreparedData(environment, data);
  const rootElement =  document.getElementById('container');

  match({routes: routes({stores}), history: browserHistory }, (error, redirectLocation, renderProps) => {
    IsomorphicRouter.prepareInitialRender(environment, renderProps).then(props => {
      ReactDOM.render(<Router {...props} />, rootElement);
    });
  });

My route(s):

<Route path="/" component={App} queries={ViewerQuery}/>

And the ViewerQuery:

export default {
  viewer: () => Relay.QL`query { viewer }`,
};

Server reads correctly the app props, so i think that is something wrong in my client render function.

minheq commented 8 years ago

Confirming this issue, I'm facing the same error in my current application, where on backend it works but not on the client.

However, by downgrading the version of isomorphic-relay and isomorphic-relay-router to version 0.7.1 and 0.8.1 respectively, it does not throw this error.

My guess is that it might be due to version conflict, because I didn't see any possible breaking change introduced in the newer versions.

@saltas888 I didn't open the issue because I have very limited time, to reproduce this issue. But you seem to have it ready, do you think you could reproduce this issue so it is easier for the maintainer? ^^ Thanks!

saltas888 commented 8 years ago

Ok so just found the solution, I have checked the package.json of this module. It uses
"react-relay": "0.9.3", "react-router": "^2.3.0".

So i had to downgrade react router from 2.6.0 to 2.5.2 , and to strict the react-relay version(I'm not sure if this helps) from ^0.9.3 to 0.9.3 and then to remove the react-relay-router from my package.json.

Then it works.

I think that the author should add dependencies in this module.

hung-phan commented 8 years ago

Have the same problem with:

    "isomorphic-relay": "^0.7.3",
    "isomorphic-relay-router": "^0.8.3",
    "react-router": "^2.8.1",
    "react-router-relay": "^0.13.5",
denvned commented 8 years ago

You must not have react-router-relay in your dependencies if you already depend on isomorphic-relay-router, otherwise you might get module conflicts, especially if you are using NPM v2. Try to remove react-router-relay from dependencies, delete your _nodemodules, and do clean install watching NPM warnings.

Generally, make sure you have only one copy of each of the following modules in your whole _nodemodules tree including nested modules:

hung-phan commented 8 years ago

@denvned. Do you have any example that use React Component for router instead of raw object like this? https://github.com/denvned/isomorphic-relay-router/blob/287597565798f2bd7dee71757d9dae592144529a/examples/todo/src/routes.js

hung-phan commented 8 years ago

My current routes are written as:

import React from 'react';
import Relay from 'react-relay';
import useRelay from 'react-router-relay';
import { browserHistory, createMemoryHistory, Router, Route, applyRouterMiddleware } from 'react-router';
import ViewerQuery from 'client/queries/viewer';
import Todos from 'client/components/todos/index.jsx';
import StaticPage from 'client/components/static-page/index.jsx';

export const getClientHistory = () =>
  browserHistory;

export const getServerHistory = (url) =>
  createMemoryHistory(url);

export const getRoutes = (history) => (
  <Router
    history={history}
    render={applyRouterMiddleware(useRelay)}
    environment={Relay.Store}
  >
    <Route path="/" component={Todos} queries={ViewerQuery} />
    <Route path="/static-page" component={StaticPage} />
  </Router>
);
denvned commented 8 years ago

@hung-phan You can use createRoutes to convert a <Route> component tree to the corresponding route object. Here is an example: https://github.com/denvned/isomorphic-relay-boilerplate/blob/9ff4df83a9c2a8ae9068098204001618e960f31c/frontend/src/routes.js

hung-phan commented 8 years ago

After downgrade react-router, remove "react-router-relay", try example in main repo. I still have the same problem. Any idea? My repo https://github.com/hung-phan/koa-react-isomorphic/tree/features/relay

denvned commented 8 years ago

@hung-phan The problem in your app is that you are trying to pass <Router> instead of a route object to the match function. See my comment above with an example of correct usage.

denvned commented 8 years ago

BTW, you don't need to downgrade react-router.

hung-phan commented 8 years ago

ah, I tried that yesterday but it didn't work.

routes.jsx

export default createRoutes(
  <Route path="/">
    <IndexRoute component={Todos} queries={ViewerQuery} />
    <Route path="static-page" component={StaticPage} />
  </Route>
);

client.js

export function prepareInitialRender(routes, domNode) {
  match({ routes, history: browserHistory }, (error, redirectLocation, renderProps) => {
    if (error) {
      navigateTo('/500.html');
    } else if (redirectLocation) {
      navigateTo(redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {
      IsomorphicRouter.prepareInitialRender(Relay.Store, renderProps)
        .then(props => {
          ReactDOM.render(<Router {...props} />, domNode);
        });
    } else {
      navigateTo('/404.html');
    }
  });
}

export default function (routes, domNode) {
  if (process.env.SERVER_RENDERING) {
    IsomorphicRelay.injectPreparedData(Relay.Store, window.prerenderData);
  }

  prepareInitialRender(routes, domNode);
}
denvned commented 8 years ago

@hung-phan That part of your code now looks correct.

hung-phan commented 8 years ago

Except it doesn't not work and has the same problem as the issue title.

denvned commented 8 years ago

@hung-phan Your project is complex, there are might be problems in other parts as well. I have no opportunity to debug it for you, but a minimal repo reproducing the error is welcome.

hung-phan commented 8 years ago

ok, thanks @denvned. Let me try to make it simple

hung-phan commented 8 years ago

https://github.com/hung-phan/koa-react-isomorphic/tree/minimal-branch. This is the repo after I remove all unnecessary code for debugging this error. It works for server rendering but getting error in client.

This is the code I use in server rendering: https://github.com/hung-phan/koa-react-isomorphic/blob/minimal-branch/app/server/middlewares/custom/prerender.js

denvned commented 8 years ago

@hung-phan Wow, I imagined a minimal repro differently than that. By minimal I meant something that is more like the Todo example in this repository.

hung-phan commented 8 years ago

I updated the branch https://github.com/hung-phan/koa-react-isomorphic/tree/minimal-branch.

denvned commented 8 years ago

@hung-phan Can you reproduce it without recompose and recompose-relay?

hung-phan commented 8 years ago

Updated. https://github.com/hung-phan/koa-react-isomorphic/tree/minimal-branch. Still have the same problem.

denvned commented 8 years ago

@hung-phan You need to remove history from the dependencies: https://github.com/hung-phan/koa-react-isomorphic/blob/329b856bf3991c95beb77e6996f87c877225a370/package.json#L10

hung-phan commented 8 years ago

Is that the solution? Updated

denvned commented 8 years ago

@hung-phan You can try, and we will see. At least it removes the version conflict with history dependency in react-router.

hung-phan commented 8 years ago

Already removed and reinstalled, same problem.

denvned commented 8 years ago

@hung-phan Did you remove _nodemodules completely, and did fresh npm install? Did npm show any warnings?

denvned commented 8 years ago

@hung-phan Also, is the problem reproduced without webpack-isomorphic-tools?

hung-phan commented 8 years ago

Only this one

npm WARN deprecated babel@6.5.2: Babel's CLI commands have been moved from the babel package to the babel-cli package
npm WARN deprecated lodash.isarray@4.0.0: This package is deprecated. Use Array.isArray.
npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated minimatch@0.2.14: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated lodash@1.0.2: lodash@<3.0.0 is no longer maintained. Upgrade to lodash@^4.0.0.
npm WARN deprecated graceful-fs@1.2.3: graceful-fs v3.0.0 and before will fail on node releases >= v7.0. Please update to graceful-fs@^4.0.0 as soon as possible. Use 'npm ls graceful-fs' to find it in the tree.
npm WARN deprecated lodash.assign@4.2.0: This package is deprecated. Use Object.assign.
npm WARN estraverse-fb@1.3.1 requires a peer of estraverse@* but none was installed.

I don't think it is the problem

hung-phan commented 8 years ago

Yes, I can remove it all but still. the problem is the client not the server

denvned commented 8 years ago

@hung-phan But you use webpack-isomorphic-tools when packing the client bundle.

hung-phan commented 8 years ago

Removed webpack-isomorphic-tools. Still have the same problem.

denvned commented 8 years ago

@hung-phan Can you remove everything else not required for reproducing this error (webpack plugins and loaders, devDependencies, babel transforms, etc), and update your minimal-branch?

denvned commented 8 years ago

@hung-phan Also, can you create a parallel minimal branch that uses react-router-relay instead of isomorphic-relay-router, to make sure the error occurs only with isomorphic-relay-router, and not with react-router-relay as well.

hung-phan commented 8 years ago

Ok, @denvned

hung-phan commented 8 years ago

https://github.com/hung-phan/koa-react-isomorphic/tree/minimal-branch and https://github.com/hung-phan/koa-react-isomorphic/tree/minimal-branch-react-relay-router

denvned commented 8 years ago

@hung-phan Change this to the following:

<Router 
  environment={Relay.Store}
  history={browserHistory}
  render={applyRouterMiddleware(useRelay)}
  routes={routes}
/>

And check that the react-router-relay branch does not produce the error.

hung-phan commented 8 years ago

Updated. minimal-branch-react-relay-router doesn't throw the error.

denvned commented 8 years ago

@hung-phan Thank you. I think we are close. Please also disable HMR/hot reload, remove common entry point from here, and remove the following plugins from your webpack configs and check again:

hung-phan commented 8 years ago

Updated

denvned commented 8 years ago

@hung-phan Does minimal-branch after the changes still produce the error, and minimal-branch-react-relay-router does not?

hung-phan commented 8 years ago

Yes

arvigeus commented 8 years ago

I have the same "prop not supplied" problem using kyt-starter-universal. Looking forward to see how this issue will unfold. If this does not resolve my problem, I'll open another issue.

denvned commented 8 years ago

@hung-phan I tried to debug your app, and found that your resulting app.js bundle contains two copies of the same modules from react-router-relay, one from react-router-relay/lib, and the other from react-router-relay/es. For example, there are two copies of RelayRouterContext, and QueryAggregator... The reason is that webpack 2 resolves react-router-relay to react-router-relay/es/index.js while isomorphic-relay-router imports also some internals from react-router-relay/lib, so we end up using two builds of react-router-relay.

I think I resolved this in isomorphic-relay-router v0.8.4, can you try it?

@arvigeus Probably you are facing the same issue as you are using webpack 2 too, so you can also try v0.8.4.

hung-phan commented 8 years ago

ok, Thanks @denvned. This info is very helpful

arvigeus commented 8 years ago

It worked. @denvned, you have no idea how much this means for me. I was stuck with this problem for a week. Your small correction had a big impact. Thank you!

minheq commented 8 years ago

Indeed it did @arvigeus .So the issue was with webpack 2.... The update is brilliant, thanks @denvned a lot! YEAH!

denvned commented 8 years ago

Thank you to @hung-phan for cooperation and patience.

hung-phan commented 8 years ago

😅 , thanks @denvned.