4

I am starting out with Relay and trying to make my routing work properly. Unfortunately, I am not having much of luck.

Here is the error I am getting:

Uncaught TypeError: Component.getFragment is not a function

Here is the code I have for your reference:

index.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import Relay from 'react-relay';
import {Router, Route, IndexRoute, browserHistory} from 'react-router';
import {RelayRouter} from 'react-router-relay';

import App from './modules/app';
import Home from './modules/home';

const AppQueries = {
  store: (Component) => Relay.QL `query {
    store {
      ${Component.getFragment('store')}
    }
  }`
};

ReactDOM.render(
  <RelayRouter history={browserHistory}>
    <Route path='/' component={App} queries={AppQueries}>
      <IndexRoute component={Home}/>
    </Route>
  </RelayRouter>, 
document.getElementById('ch-root'));

app.jsx

import React, {Component} from 'react';
import Relay from 'react-relay';
import Header from './ui/header';
import Footer from './ui/footer';

class App extends Component {
  render() {
    return (
      <div id="ch-container">
        <Header/>
        <section id="ch-body">
          {this.props.children}
        </section>
        <Footer/>
      </div>
    );
  }
}

App = Relay.createContainer(App, {
  fragments: {
    store: (Component) => Relay.QL `
      fragment on Store {
        ${Component.getFragment('store')}
      }
     `
  }
});

export default App;

home.jsx

import React, {Component} from 'react';
import Relay from 'react-relay';
import Loader from './ui/loader';
import AccountSelector from './account/account-selector';

const APP_HOST = window.CH_APP_HOST;
const CURR_HOST = `${window.location.protocol}//${window.location.host}`;

class Home extends Component {
  state = {
    activeAccount: null,
    loading: true
  }

  render() {
    const {activeAccount, loading} = this.state;

    if (loading) {
      return <Loader/>;
    }

    if (!activeAccount && !loading) {
      return <AccountSelector/>;
    }

    return (
      <h1>Hello!</h1>
    );
  }
}

Home = Relay.createContainer(Home, {
  fragments: {
    store: () => Relay.QL `
      fragment on Store {
        accounts {
          unique_id,
          subdomain
        }
      }
     `
  }
});

export default Home;

UPDATE

I made few changes suggested by freiksenet as below. But that raises the following two issues:

  1. What would happen when I change the route and a component other than Home gets rendered by the App component?
  2. I now get this error:

Warning: RelayContainer: Expected prop store to be supplied to Home, but got undefined. Pass an explicit null if this is intentional.

Here are the changes:

index.jsx

const AppQueries = {
  store: () => Relay.QL `query {
    store 
  }`
};

app.jsx

import Home from "./home";

...

App = Relay.createContainer(App, {
  fragments: {
    store: () => Relay.QL `
      fragment on Store {
        ${Home.getFragment('store')}
      }
     `
  }
});
2
  • The error means that it doesn't know what Component is. You'll have to import it in a similar fashion to how you imported App and Home. I'm assuming the error is generated on the index file? Commented Apr 18, 2016 at 7:01
  • @Moon Response to your UPDATE 1: Question 2: You didn't pass any query for Home component. In index.jsx file, Change <IndexRoute component={Home}/> to <IndexRoute component={Home}/> queries={AppQueries}. Question 1: As @freiksenet has already mentioned, App doesn't have to be container. The other component(s) rendered by App just needs to have necessary fragments defined. Commented Apr 18, 2016 at 22:06

1 Answer 1

4

Fragment definitions don't actually get Components as arguments, but a map of variables of the container, you only need to use them to have conditional fragments based on variable values.

Relay Route queries don't accept any arguments.

Here are the changes you need to make.

Route queries in Relay just need to specify the root query you are going to retrieve in this route, without the fragment.

index.jsx

const AppQueries = {
  store: () => Relay.QL `query {
    store 
  }`
};

Your App component actually doesn't use any relay data, so you can just export normal component instead of container.

export default class App extends Component {

If you'd need to pass some Relay data to it, you don't need to include child fragments, because fragments inclusion is only needed when you directly render other containers as direct children (not as this.props.children).

Then in Router you need to move the queries to Home.

ReactDOM.render(
  <RelayRouter history={browserHistory}>
    <Route path='/' component={App}>
      <IndexRoute component={Home} queries={AppQueries} />
    </Route>
  </RelayRouter>, 
document.getElementById('ch-root'));
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot for the response. I updated my code as suggested and then updated my question with new observations.
@Moon Aha. It seems I misunderstood what you are trying to do a bit. Corrected now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.