Giter VIP home page Giter VIP logo

found-relay's People

Contributors

chentsulin avatar coleturner avatar crohlfs avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dminkovsky avatar itajaja avatar jquense avatar leoschweizer avatar renovate-bot avatar renovate[bot] avatar taion avatar xdissent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

found-relay's Issues

Retry makes requests, but does not re-render route after

I have updated to v0.3.0-alpha.5 and the retry button now makes a request correctly to my server, but it does cause a re-render on the route so the new state can be displayed without requiring the user to navigate away from the page and come back.

A good test would be that a component has a state when in error and when not in error. When latest response is an error response of some kind (bad json, bad connection, etc.) it shows the error state (e.g. "There has been an error"). When the retry is called the request is made and it causes a re-render which displays the UI if there were no error.

Server-side rendering

Hi, I'm looking into moving towards found from react-router. One requirement for me is hydrating data from the server, as in https://github.com/denvned/isomorphic-relay-router

I'm close to being able to contribute an SSR example for found-relay, but with one issue, which is the client-side router doesn't seem to render pre-hydrated store data.

(note i'm referring here to "relay classic")

I'm able to serialize the data on the server and then inject into the client-side relay store:

const preparedData = JSON.parse(document.getElementById('preparedData').text);
const storeData = environment.getStoreData();
preparedData.forEach(({ query: concreteQuery, response }) => {
  const query = fromGraphQL.Query(concreteQuery);
  storeData.handleQueryPayload(query, response);
});

But I'm not sure where to go from here, when I render the found Router:

const Router = createFarceRouter({
  historyProtocol: new BrowserProtocol(),
  historyMiddlewares: [queryMiddleware],
  routeConfig: routes,
  render: createRender({}),
});

const root = document.getElementById('root');

ReactDOM.render(
  <Router resolveElements={createResolveElements(environment)} />,
  root,
);

found seems to render nothing in the first pass. Does this feature need to be explicitly added to found or is there something I'm missing?

Just one example

Hi,

Just one example to use it can be very useful :)

Thanks in advance

Garbage collection starts too early when using react-static-container in the render function

When using react-static-container in the render function as discussed #42 there is an issue when updating variables. It seems that ReadyStateRenderer calls this.selectionReference.dispose() too early. After the data has been downloaded, the subscriptions for fragment containers located inside the static container which is blocking updates from above it in the render tree, are updated for the old variables by calling setState directly for the individual fragment containers. At this point the data for the old variables has already been removed leaving undefined as values for the fields that use the variable as an argument.

Deprecated RelayModernEnviroment method invoked

I got this deprecation warning. This might be from modern/QuerySubscription module.

Warning: environment.streamQuery() is deprecated. Update to the latest version of react-relay, and use environment.execute().

Fix QuerySubscription bugs

  • Use explicit flag for first render rather than check readyState.retry
  • Clear readyState when calling retry (possibly only when retry does not succeed synchronously)
  • Fire listeners on errors outside of initial fetch

Q: resetting relay environment + forceUpdate unmount/remounts

Regarding: facebook/relay#233 (comment)

We had this working well with older relay and react-router-relay. This worked as creating a new environment on auth change, and running forceUpdate().

Now that we have switched to relay 1.1 and found-relay, while this same method works, it is unMounting/reMounting our top level root route component called AppFrame. This is causing a problem because our NotificationCenter is rendered within AppFrame, and the unmounted NotificationCenter receives the auth change message (e.g. Signed out) before the new one is mounted, so our auth user notifications are disappearing.

I tried killing the forceUpdate which no longer unmounts AppFrame, but the problem is that AppFrame is still rendering with the old relay enviroment.

Routes:

    return (
      <Route
        Component={AppFrame}
        query={graphql`
          query appRoutes_DummyApp_Query {
            currentUser {
              ...AppFrame_currentUser
            }
          }`
        }
      >
        {this.resolve(AuthenticationRoutes)}
        {this.resolve(HomeRoutes)}
        {this.resolve(SamplesRoutes)}
        {this.resolve(OrganizationRoutes)}
        {this.resolve(ContactRoutes)}
      </Route>
    )

Here is our reset:

// @flow

import {Environment, Network, RecordSource, Store} from 'relay-runtime'
import {JSON_META} from '../util/Fetch/Fetch'
import Logger from '../util/Logger'

const log = Logger.get('CurrentRelay')

/**
 * Define a function that fetches the results of an operation (query/mutation/etc)
 *
 * @param operation
 * @param variables
 * @param cacheConfig
 * @param uploadables
 * @returns Promise
 */
function fetchQuery (
  operation,
  variables,
  cacheConfig,    // eslint-disable-line no-unused-vars
  uploadables     // eslint-disable-line no-unused-vars
) {
  return fetch('/graphql', {
    ...JSON_META,
    method: 'POST',
    body: JSON.stringify({
      query: operation.text, // GraphQL text from input
      variables
    })
  }).then(response => {
    return response.json()
  })
}

// https://github.com/facebook/relay/issues/233 shows how to reset Relay Store using Relay.Environment
class CurrentRelay {
  environment: null

  constructor () {
    this.reset()
  }

  reset () {
    this.environment = new Environment({
      network: Network.create(fetchQuery),
      store: new Store(new RecordSource())
    })
    log.debug('reset completed for Relay environment')
  }
}

const currentRelay = new CurrentRelay()
export default currentRelay

And in our App:

  onAuthChange = () => {
    // need to reset our Relay.Store on auth change to clear the cache
    currentRelay.reset()
    this.forceUpdate()
  }

While I can work around this in some kind of global notification queue or delay, I first want to stop and ask if this is the prefered way of handling such thing.

Is there a better way to make AppFrame aware of the new environment after reset?

Example showing subscriptions

Hi @taion! I want to first thank you for all of your work building routing solutions for Relay. Much appreciated!

I know that documentation is forthcoming for this project, but I'm wondering if it would be relatively trivial for you to add a subscription example to one of the existing Relay Modern examples? It's not clear to me, for example, how found-relay's route config should coexist with Relay's requestSubscription.

Using dynamic values as Relay query variables

This is more of a question about effective paradigms when working with Relay Modern via found-relay than an issue but I feel there could be a better pattern for passing dynamic values to Relay queries.

I've come across two scenarios where I need to set Relay query variables to dynamic values:

  1. URL path or querystring parameters - eg. /myroute/:id or /myroute?id=xyz
  2. Application state - eg. Redux store

At the moment I achieve this like so:

<Route
  path='/path-one/:id'
  Component={SomeComponent}
  query={someQuery}
  prepareVariables={params => ({
    ...params,
    id: `${reduxStore.getState().id}`,
  })}
/>

<Route
  path='/path-two/:id'
  Component={SomeComponent}
  query={someQuery}
  prepareVariables={params => ({
    ...params,
    id: window.location.pathname.split('/')[3],
  })}
/>

But I feel this is fairly crude, so I am wondering if anyone has devised a cleaner pattern?

Uncaught (in promise) TypeError: this.pendingRequest.dispose is not a function

With 0.3.0-alpha.8 version this bug just appear. If I click on a Link while a query is running, I got this error:

Uncaught (in promise) TypeError: this.pendingRequest.dispose is not a function
    at QuerySubscription.dispose (http://localhost:3000/static/js/bundle.js:14996:27)
    at http://localhost:3000/static/js/bundle.js:15411:27
    at Array.forEach (<anonymous>)
    at Resolver.updateQuerySubscriptions (http://localhost:3000/static/js/bundle.js:15409:33)
    at Resolver._callee$ (http://localhost:3000/static/js/bundle.js:15291:41)
    at tryCatch (http://localhost:3000/static/js/bundle.js:5403:40)
...

Authentication Check

How to do authentication check globally after relay modern query fired?
i.e. this.props.viewer.user !== null

Parent Route jsx without render/component - Relay routes without a render method must specify a component.

I'm trying to get running after a conversion to modern, and bumped into https://github.com/4Catalyzer/found-relay/blob/next/src/modern/ReadyStateRenderer.js#L85:

Relay routes without a render method must specify a component.

Here is a sample:

  <Route path='/samples'>
    <Route path='layout' getComponent={() => import('./Grid').then(module => module.default)} />
    <Route path='text' getComponent={() => import('./Text').then(module => module.default)} />
  </Route>

Is a parent Route jsx not supported as it was with react-router/react-relay-router or am I just missing something? It seems this is ok with found, but not with found-relay?

Uncaught (in promise) TypeError: Cannot read property 'retain' of undefined

Hey all,

I am trying to setup a relay modern environment. relay-compiler runs fine and produces the necessary files. but I am getting the following error in console.

Uncaught (in promise) TypeError: Cannot read property 'retain' of undefined
at RelayModernEnvironment.retain (webpack:///./~/relay-runtime/lib/RelayModernEnvironment.js?:73:23)
at QuerySubscription.retain (webpack:///./~/found-relay/lib/modern/QuerySubscription.js?:122:29)
at eval (webpack:///./~/found-relay/lib/modern/QuerySubscription.js?:68:44)
at Promise (<anonymous>)
at F (webpack:///./~/core-js/library/modules/_export.js?:35:28)
at QuerySubscription.fetch (webpack:///./~/found-relay/lib/modern/QuerySubscription.js?:65:27)
at eval (webpack:///./~/found-relay/lib/modern/Resolver.js?:82:63)
at Array.map (native)
at Resolver._callee$ (webpack:///./~/found-relay/lib/modern/Resolver.js?:81:44)
at tryCatch (webpack:///./~/regenerator-runtime/runtime.js?:65:40) 

I have the following package versions in package.json

"farce": "^0.2.1",
"found": "^0.3.0",
"found-relay": "^0.3.0-alpha.1",
"graphql": "^0.10.1",
"graphql-relay": "^0.5.2",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-relay": "^1.0.0",
"webpack": "^2.6.1"

Thanks for all the help.

Properly do tree traversal for route variables

Found is adding support for named child routes: 4Catalyzer/found#113

While things will work out-of-the-box, the route variable traversal will not be quite right; it will do a depth-first traversal of routes, which will allow routes to be affected by their earlier siblings, rather than just their ancestors.

We should modify the route traversal to actually account for the tree structure.

component gets initialised with null prop if ID is not defined in graphql schema?

The issue Im having is that my query's get executed, and I see a response coming back from the server. But my component does not receive the data via the props. At runtime it throws the following warning:

createFragmentSpecResolver: Expected prop streets to be supplied to Relay(SenderPage), but got undefined. Pass an explicit null if this is intentional.

The only difference I see from the example is that my schema does not specify IDs
so where the example has fragments like this:

fragment TodoApp_viewer on User {
id
...TodoListFooter_viewer
}

my fragments are similar but there is no viewer object and it misses the id on top. Is this mandatory for it to work? Or am I doing something else wrong.

query AppFetchStreetQuery($countrycode:String!, $postalcode:String!) {
...ListPage_streets
}

Error handling (HttpError and RedirectException) not working

First of all thanks for this great library. I enjoy working with it a lot. I just came across a problem:

I want to display a 404 page when a aNeccessaryProp is not set. So I tried throwing a HttpError when props are set but aNeccessaryProp is not set:

const routeConfig = {
  Component: MyComponent,
  query,
  render: ({ props }) => {
    if (props && props.aNeccessaryProp) {
      return <MyComponent {...props} />;
    } else if (!props.aNeccessaryProp) {
      throw new HttpError(404);
    }
    return null;
  }
};

<Route {...routeConfig} />

I thought, that handling the error in the renderError method supplied to createRender should be possible.

const render = createRender({
  renderError: ({ error }) => { // eslint-disable-line react/prop-types
    console.log('createRender error', error);
    switch (error.status) {
      case 404: return <div>404</div>;
      case 401: return <div>401</div>;
      default: return null;
    }
  },
});

But unfortunately the error is not caught: asyncToGenerator.js:20 Uncaught (in promise) RedirectException {location: "/"}

Throwing a RedirectExpection like throw new RedirectExpection({ path: '/' }) also results in an uncaught error.

So my question is: Is there something I'm doing wrong? How do you handle HttpErrors and RedirectExceptions?

Router history

@taion Hi taion, how can I listen the URL change? In relay-classic + react-router, I can get use history.listen method to listen the changes in child component. How can I do the same things now?

Capturing an instance of SnapshotRenderer

I'm currently running into an issue where I'm doing a modal that involves capturing a previous instance of SnapshotRender.

Here is my render method to better understand:

        <Main {...mainProps}>
          {isModal ? this.previousChildren : this.children()}
          {isModal && this.children()}
        </Main>

Where this.previousChildren is the previous route's SnapshotRenderer and this.children() is a modal containing this route's SnapshotRenderer.

The error I am observing:

QuerySubscription already has a listener.

The navigation I observe this is as follows:

  1. /random-slug
  • A new QuerySubscription is created
  • Subscribe is called via componentDidMount
  1. /editor/id-for-random-slug (modal: true)
  • A new QuerySubscription is created and subscribe is called via componentDidMount (for new route)

  • The old QuerySubscription will resubscribe via componentWillReceiveProps

  • /route-a is captured as previousChildren

Here is my router schema:

  <Route
    path="/"
    Component={AppWrapper}
  >

     <Route path=":nodeID" >
    <Route path="editor">
        <Route path="/" Component={NodeContainer} query={NodeQuery} />
        <Route path="version/:versionID" Component={NodeContainer} query={NodeQuery} />
        </Route>
      </Route>
      <Route path=":slug" Component={SlugContainer} query={SlugQuery} />
  </Route>

I am wondering if I am doing something wrong by capturing the instance in previousChildren or if there is a way to keep rendering a route beneath a modal.

All query being passed to a container

Let's consider a route:

<Route
        path="table"
        Component={Table}
        prepareVariables={params => ({tableId: '59abf1a01710ba3b74718220'})}
        query={tableQuery} 
/>

With a query:

graphql`
query routesTableQuery($tableId: String){
    store {
        table(id: $tableId){
            ...Table_table
        }
    }
}`

And container with a fragment:

export default createFragmentContainer(
    Table,
    graphql`
        fragment Table_table on Table {
            name
            stake
        }
    `
)

Then the Table component receives store object instead of only table.
This violates the scope separation principle.
How can I pass down only the required fragment of data?

How to make redirect from network layer?

Here is my network layer:

function fetchQuery(operation,
                    variables,
                    cacheConfig,
                    uploadables) {
	// return fetch('https://api.graph.cool/relay/v1/cj07pfjjj1nbq0148rutjhxd5', {
	return fetch('http://localhost:3010/graphql', {
		method: 'POST',
		headers: {
			'Accept': 'application/json',
			'Content-Type': 'application/json',
		},
		body: JSON.stringify({query: operation.text})
	}).then(response => {
		
		if(response.status == 401){
			throw new Error('Network response was not ok.');
// HOW TO MAKE REDIRECT TO LOGIN PAGE HERE?

		}
		

		return response.json();
	});
}

Help me please!

Named components

@taion I've converted a huge app from react-router-relay to found-relay and relay modern as you suggested. It works for the most part except for where I used named components. I made heavy use of named components in my relay classic app but have not been able to figure out how to do it with relay modern using found-relay. Any help would be much appreciated.

Retry does nothing because fetchPromise is not falsey

I have an issue I don't understand with my current Relay app using found-relay.

This line: https://github.com/4Catalyzer/found-relay/blob/e9f5fe225b33a2bb122d5ea38328c93d5f242f41/src/modern/QuerySubscription.js#L29

I have debugged and seen that while I have no requests in flight, a resolved promise is there and so it doesn't not do a proper check and refuses to make a request when I click a button I've wired up to do a retry.

Steps to reproduce

You need:

  • A relay application with a query on the route
  • Two different routes
  1. I loaded my React app and navigated to a route successfully.
  2. I then disabled my internet via the Network tab of chrome
  3. I navigated to another route with a query and it failed
  4. I then clicked on a button which executes the retry() function given to the render function of the route.

edit: Sorry early post. Updated with rest of issue

[Relay Modern] Can't pass new environment/resolver to router

We're trying to implement a resettable store and having issues passing a new Resolver to the router.
The code below is for a wrapper component around a Router that on reset() creates new source, store, network, environment and resolver instances.

But once setState() is executed, the newly-instantiated objects immediately revert back to their old values. We're pretty flummoxed by this behaviour.

reset = () => {
    const source = new RecordSource();
    const store = new Store(source);
    console.log(store); 
    const network = Network.create(this.props.fetchQuery);
    const environment = new Environment({store, network});
    const resolver = new Resolver(environment);
    this.setState({resolver});
};

render() {
    const Router = this.router;
    return <Router resolver={this.state.resolver}/>;
}

I'm grateful for any help on this.

Handle graphql server error

renderError is never called when my GraphQL server return for example :

{"errors":[{"locations":[{"column":3,"line":5}],"message":"current transaction is aborted, commands ignored until end of transaction block\n"}],"data":{"category":null}}

How catch that and redirect the user to a specific page ?

Unable to pass variables to route's query

When I use prepareVariables I provide variables for the query but in my fetch function nothing comes through.

Since there are no docs yet for this version, and there don't seem to be any tests using this feature, I was wondering if I could get some help figuring this out

I'm using Relay Modern and the latest early release. The request is made, it makes a request for the query I asked, but doesn't provide my variables to that fetch function so it fails.

Uncaught Error: QuerySubscription already has a listener.

Hi,

When mounting a ReadyStateRenderer the second time, I get the following exception.

Uncaught Error: QuerySubscription already has a listener.
    at invariant (browser.js:40)
    at QuerySubscription.subscribe (QuerySubscription.js:116)
    at SnapshotRenderer.subscribe (ReadyStateRenderer.js:121)
    at SnapshotRenderer.componentDidMount (ReadyStateRenderer.js:96)
    at eval (ReactCompositeComponent.js:264)
    at measureLifeCyclePerf (ReactCompositeComponent.js:75)
    at eval (ReactCompositeComponent.js:263)
    at CallbackQueue.notifyAll (CallbackQueue.js:76)
    at ReactReconcileTransaction.close (ReactReconcileTransaction.js:80)
    at ReactReconcileTransaction.closeAll (Transaction.js:209)

This happens when moving between the mobile and desktop layouts. I have a configuration where the root is a layout component, which depending on the viewport width either draws a MobileLayout or DesktopLayout component, with the different parts of the UI defined in route groups. When changing the width the components defined in the route groups, the different component defined in the route groups unmount and mount again in the new layout.

Redirecting doesn't trigger query call

const query = graphql`
  query socialLoginCallbackContainerQuery {
    externalLoginCallback {
      loginProvider,
      newUserName
      user {
        userName
      }
    }
  }
`;
const render = (route) => {
  if (route.props) {
    // User already has an account that is logged in so redirect them
    if (route.props.externalLoginCallback.existingUser) {
      route.props.context.store.dispatch(showLoginPopup());

      throw new RedirectException('/');
    } else {
      // associate the users account
      return (
        <SocialLoginConfrimationContainer
          newUserName={route.props.externalLoginCallback.newUserName}
          loginProvider={route.props.externalLoginCallback.loginProvider}
          returnUrl={route.props.params.returnUrl}
        />
      );
    }
  }

  return null;
};

I am using OAUTH twitter login on server side to log the user in, if they have already got an account associated my website then I want to redirect them back to the homepage. On the homepage I run a query to get the users username to show it on the screen. The problem is when I redirect the user using throw new RedirectException('/'); the query on the home route that gets the username doesn't get run again so the username never updates.

If I do this instead:

// User already has an account that is logged in so redirect them
if (route.props.externalLoginCallback.user) {
  route.props.context.store.dispatch(showLoginPopup());

  window.location.href = "/";
}

Then that will work and run the query again but it produces a full page refresh obviously. How do I use found's routing system to redirect to another route and also update the userName with the new values or re-run the root query?

Root query:

const query = graphql`
  query appContainerQuery {
    user {
      userName
    }
  }
`;

Field resolution to error

Hi

If in schema.js, I resolve userType to a graphqlError by throwing an exception, nothing is rendered at all and renderError of routes is not called.

I get the following error in browser:

[HMR] Waiting for update signal from WDS... asyncToGenerator.js:20 Uncaught (in promise) undefined step @ asyncToGenerator.js:20 (anonymous) @ asyncToGenerator.js:30 Promise rejected (async) settle @ asyncGenerator.js:71 resume @ asyncGenerator.js:57 (anonymous) @ asyncGenerator.js:51 Promise rejected (async) settle @ asyncGenerator.js:71 resume @ asyncGenerator.js:57 (anonymous) @ asyncGenerator.js:51 Promise rejected (async) onError @ QuerySubscription.js:66 (anonymous) @ RelayNetwork.js:76 Promise resolved (async) executeImpl @ execute.js:133 execute @ execute.js:102 Object.defineProperty.value @ graphql.js:78 graphqlImpl @ graphql.js:62 graphql @ graphql.js:50 fetchQuery @ createFetch.js:14 requestStream @ RelayNetwork.js:59 streamQuery @ RelayModernEnvironment.js:115 (anonymous) @ QuerySubscription.js:35 F @ _export.js:35 fetch @ QuerySubscription.js:30 (anonymous) @ Resolver.js:41 _callee$ @ Resolver.js:40 tryCatch @ runtime.js:65 invoke @ runtime.js:303 prototype.(anonymous function) @ runtime.js:117 resume @ asyncGenerator.js:44 (anonymous) @ asyncGenerator.js:37 F @ _export.js:35 send @ asyncGenerator.js:24 exports.default.AsyncGenerator.next @ asyncGenerator.js:105 _callee$ @ resolveRenderArgs.js:3 tryCatch @ runtime.js:65 invoke @ runtime.js:303 prototype.(anonymous function) @ runtime.js:117 resume @ asyncGenerator.js:44 (anonymous) @ asyncGenerator.js:37 F @ _export.js:35 send @ asyncGenerator.js:24 exports.default.AsyncGenerator.next @ asyncGenerator.js:105 _callee$ @ createBaseRouter.js:11 tryCatch @ runtime.js:65 invoke @ runtime.js:303 prototype.(anonymous function) @ runtime.js:117 step @ asyncToGenerator.js:17 (anonymous) @ asyncToGenerator.js:35 F @ _export.js:35 (anonymous) @ asyncToGenerator.js:14 resolveMatch @ createBaseRouter.js:11 componentDidMount @ createBaseRouter.js:58 (anonymous) @ ReactCompositeComponent.js:264 measureLifeCyclePerf @ ReactCompositeComponent.js:75 (anonymous) @ ReactCompositeComponent.js:263 notifyAll @ CallbackQueue.js:76 close @ ReactReconcileTransaction.js:80 closeAll @ Transaction.js:209 perform @ Transaction.js:156 batchedMountComponentIntoNode @ ReactMount.js:126 perform @ Transaction.js:143 batchedUpdates @ ReactDefaultBatchingStrategy.js:62 batchedUpdates @ ReactUpdates.js:97 _renderNewRootComponent @ ReactMount.js:319 _renderSubtreeIntoContainer @ ReactMount.js:401 render @ ReactMount.js:422 (anonymous) @ client.js:45 __webpack_require__ @ bootstrap 8dbbe51โ€ฆ:659 fn @ bootstrap 8dbbe51โ€ฆ:85 (anonymous) @ amd-options.js:2 __webpack_require__ @ bootstrap 8dbbe51โ€ฆ:659 module.exports @ bootstrap 8dbbe51โ€ฆ:708 (anonymous) @ bootstrap 8dbbe51โ€ฆ:708 client?dc71:41 [WDS] Hot Module Replacement enabled.

which is caused by QuerySubscriber --> fetch--> onError() --> reject()

graphql response is as follows:

response json: { errors: [ { message: 'this is my error message', locations: [Object], path: [Object] } ], data: { viewer: { id: 'VXNlcjptZQ==', todos: null, numTodos: 2, numCompletedTodos: 1 } } } response json: { errors: [ { message: 'this is my error message', locations: [Object], path: [Object] } ], data: { viewer: { todos: null, id: 'VXNlcjptZQ==', numTodos: 2, numCompletedTodos: 1 } } }

How do you route to a specific item?

I'm very new to GraphQL and Relay. I hit a wall today trying to figure out how to route to a single item, ie can't figure out how to pass the a route param into graphql query.

For example say I have a route /products/1 and I pluck this idea from location props. How do I pass this in as an argument in the query fragment?

Eg node(id: productId) {
title
price
etc
}

It's look like we can't render a component with children in pending state

With that:

<Route
        Component={Layout}
        queries={LayoutQueries}
        prepareParams={prepareParamsLayout}
        render={renderLayout}
      >
        <Route
          Component={Content}
          queries={ContentQueries}
          prepareParams={prepareParamsContent}
          render={renderContent}
        />
      </Route>

And a generic render who return a loading component if no Component or props.

I want to render Layout all the time, but actually i receive null Component in renderLayout call of Layout while Content data is loading.

Sorry for my english, I am french ^^

How to reset Relay environment

I have a mutation that needs to reset the Relay environment. The suggested solution is to use new Relay.Environment() to create a new environment instead of manually working through the store. But I don't see how I could hand off the new environment to found.

More details in my StackOverflow question.

Throw new HttpError in render method doesn't work

It's working in route without queries prop.

I throw HttpError in render method and got that:

asyncToGenerator.js?74f6:20 Uncaught (in promise) TypeError: Cannot read property 'replaceChild' of null
replaceChildWithTree	@	DOMLazyTree.js?1b54:69
dangerouslyReplaceNodeWithMarkup	@	Danger.js?9fba:41
dangerouslyReplaceNodeWithMarkup	@	DOMChildrenOperations.js?568f:124
_replaceNodeWithMarkup	@	ReactCompositeComponent.js?d2b3:784
_updateRenderedComponent	@	ReactCompositeComponent.js?d2b3:774
_performComponentUpdate	@	ReactCompositeComponent.js?d2b3:724
updateComponent	@	ReactCompositeComponent.js?d2b3:645
receiveComponent	@	ReactCompositeComponent.js?d2b3:547
receiveComponent	@	ReactReconciler.js?399b:125
_updateRenderedComponent	@	ReactCompositeComponent.js?d2b3:754
_performComponentUpdate	@	ReactCompositeComponent.js?d2b3:724
updateComponent	@	ReactCompositeComponent.js?d2b3:645
receiveComponent	@	ReactCompositeComponent.js?d2b3:547
receiveComponent	@	ReactReconciler.js?399b:125
_updateRenderedComponent	@	ReactCompositeComponent.js?d2b3:754
_performComponentUpdate	@	ReactCompositeComponent.js?d2b3:724
updateComponent	@	ReactCompositeComponent.js?d2b3:645
performUpdateIfNecessary	@	ReactCompositeComponent.js?d2b3:561
performUpdateIfNecessary	@	ReactReconciler.js?399b:157
runBatchedUpdates	@	ReactUpdates.js?8e6b:150
perform	@	Transaction.js?f15f:140
perform	@	Transaction.js?f15f:140
perform	@	ReactUpdates.js?8e6b:89
flushBatchedUpdates	@	ReactUpdates.js?8e6b:172
closeAll	@	Transaction.js?f15f:206
perform	@	Transaction.js?f15f:153
batchedUpdates	@	ReactDefaultBatchingStrategy.js?e9be:62
enqueueUpdate	@	ReactUpdates.js?8e6b:200
enqueueUpdate	@	ReactUpdateQueue.js?6531:24
enqueueSetState	@	ReactUpdateQueue.js?6531:209
ReactComponent.setState	@	ReactComponent.js?702a:63
updateElement	@	createBaseRouter.js?6395:341
_callee$	@	createBaseRouter.js?6395:310
tryCatch	@	runtime.js?1aab:63
invoke	@	runtime.js?1aab:337
prototype.(anonymous function)	@	runtime.js?1aab:96
step	@	asyncToGenerator.js?74f6:17
(anonymous function)	@	asyncToGenerator.js?74f6:28

TypeError: Cannot read property 'Container' of undefined

Hello!
I'm getting this error every time whatever I do

TypeError: Cannot read property 'Container' of undefined
./node_modules/found-relay/lib/RelayRouteRenderer.js
node_modules/found-relay/lib/RelayRouteRenderer.js:45
  42 |     render: _propTypes2.default.func
  43 |   }).isRequired
  44 | }).isRequired,
> 45 | Component: _reactRelay2.default.PropTypes.Container,
  46 | environment: _reactRelay2.default.PropTypes.Environment,

May be I'm way too much tired but i can't figure out why do i even get it

Thank you for help!

Multiple query roots for a single route

In react-router-relay I was able to create multiple query roots on a single route, i.e. a route could have a two queries like:

const RootQuery = {
  foo: graphql`
    query {
      node (idOfAFooNode: $Id)  {
        ...ComponentFragment_foo
      }
    }
   `,
  bar: graphql`
    query {
      node (id: $IdOfABarNode)  {
        ...ComponentFragment_bar
      }
    }
   `
};

This way my root component would have this.props.foo and this.props.bar.

Is this possible in found-relay? I've tried to look through the examples for relay-modern + code and can't determine if it is possible to create multiple query roots on a single route? Maybe there is another way you folks have thought about a way to do this?

Isomorphic example

Hey,

I was just trying to integrate this package with universal-webpack. I don't know if it's a bug or config error or if what I'm trying to do is unsupported.

The question and code is all here:
https://stackoverflow.com/questions/45246891/getting-found-relay-to-work-with-universal-webpack

The error showing up when a page gets requested from the browser is Cannot read property pathname of undefined. And it's getting thrown from this call:

ReactDOMServer.renderToString(element)

Route's getComponent and render props

https://github.com/taion/relay-todomvc/tree/found-modern works great. But when I use getComponent in place of Component={TodoList} in routes file and add render props like this.

export default makeRouteConfig(
  <Route
    path="/"
    Component={TodoApp}
    query={graphql`
      query routes_TodoApp_Query {
        viewer {
          ...TodoApp_viewer
        }
      }
    `}
  >
    <Route
      getComponent={() => {
        import('./components/TodoList').then(module => module.default);
      }}
      render={({ Component, props }) => (
        Component && props ? (
          <Component {...props} />
        ) : (
          <div><small>Loading</small></div>
        )
      )}
      query={TodoListQuery}
      prepareVariables={params => ({ ...params, status: 'any' })}
    />
    <Route
      path=":status"
      getComponent={() => {
        import('./components/TodoList').then(module => module.default);
      }}
      render={({ Component, props }) => (
        Component && props ? (
          <Component {...props} />
        ) : (
          <div><small>Loading</small></div>
        )
      )}
      query={TodoListQuery}
    />
  </Route>,
);

Component in the render function is undefined and it shows Loading.
Not sure if this is a known issue or not. Would love to hear what causes this.

Redux and found-relay

Hi,

I was wondering if they are any known issues with using found-relay and redux. When I do

screen shot 2017-06-16 at 12 43 53 pm

I essentially can not use redux. When I fire actions nothing happens.

But when I replace <Router resolver={new Resolver(environment)} /> with <App /> essentially removing the router - I can fire the actions again. Are their any conflicts with store in router and redux? thanks.

Support Relay 2

Hi.

Any plan to support Relay Modern?

I am big fan of found,
and looking forward to use the new relay with it.

Programatic navigation doesn't render component when passing url param

Hi

I am trying to navigate to a route programatically which has a url param after a mutation commit but it renders a blank page:

screen shot 2017-09-15 at 20 04 03

Here are my routes:

<Route 
  path='/'
  Component={ App }
>
  <Route 
    Component={ Dashboard }
    query={graphql`
    query routes_Dashboard_Query {
      business {
        ...Dashboard_business
      }
    }
  `} 
  />
  <Route path='configure-booking'>
    <Route 
      Component={ ConfigureShift }
      query={ configureShiftQuery } 
      prepareVariables={ params => ({ ...params, bookingId: 'any' }) }
    />
    <Route
      Component={ ConfigureShift }
      query={ configureShiftQuery }
      path=':bookingId'
      render={({ Component, props }) => (
        Component && props ? (
          <Component {...props} />
        ) : <Loader />
      )}
    />
  </Route>
</Route>

And here is the mutation code:

export default function commit(data, props, env = environment) {
  return commitMutation(env, {
    mutation,
    variables: { 
      positions: data.positions,
      eventId:   data.eventId,
      venueId:   data.venueId
    },
    onCompleted: response => {
      props.router.replace(`configure-booking/${response.shift.id}`);
    },
    onError: err => console.error(err)
  });
}

If i reload the page it works as expected:

props.router.replace(`configure-booking/${response.shift.id}`);
window.location.reload();

But this seems to defeat the whole purpose.
Am i doing something wrong or is it a bug?

RedirectException causing TypeError

I just posted this to SO -- sorry for the issue noise as there's a good chance it is user error.

I'm trying to redirect unauthenticated users to a login page by throwing a RedirectException. To get the ball rolling, I'm using the relay-todomvc-found-modern demo and trying to redirect the user to a login page if the status variable is active. The redirect works if I visit /completed and click the link for /active, but throws TypeError: Cannot read property 'getHostNode' of null if I directly visit /active.

Starting with the relay-todomvc-found-modern demo, I added the following lines:

import { RedirectException } from 'found';

...
render() {
     if (status === 'active') {
         throw new RedirectException({pathname: '/login'})
     }
}
...

where /login leads to a component that is copy/pasted from TodoList (with name changes as necessary) that is set up with the following route:

<Route
  path="/"

...

    <Route
        path="login"
        Component={Login}
        query={LoginQuery}
        prepareVariables={params => ({ ...params, status: 'any' })}
    />

...

</Route>

And the LoginQuery is

const LoginQuery = graphql`
    query routes_Login_Query($status: String!) {
        viewer {
            ...Login_viewer
        }
    }
`;

The Login component is exactly the same as the TodoList components, except without the RedirectException and with name changes as necessary.

Invalid prop/context `relay` supplied to `Relay(VideoList)`

I'm writing an isomorphic app and the server is rendering everything fine, but in the browser (Chrome) I get these errors:

warning.js:36 Warning: Failed context type: Invalid prop/context `relay` supplied to `Relay(VideoList)`, expected `undefined` to be an object with an `environment` and `variables`.
    in Relay(VideoList)
    in section (created by Main)
    in section (created by Main)
    in Main (created by AppFrame)
    in AppFrame
    in Renderer (created by BaseRouter)
    in StaticContainer (created by BaseRouter)
    in StaticContainer (created by BaseRouter)
    in BaseRouter (created by Connect(BaseRouter))
    in Connect(BaseRouter) (created by FarceRouter)
    in Provider (created by FarceRouter)
    in FarceRouter

buildReactRelayContainer.js:40 Uncaught (in promise) TypeError: Cannot read property 'environment' of undefined
    at ContainerConstructor (buildReactRelayContainer.js:40)
    at ReactCompositeComponent.js:305
    at measureLifeCyclePerf (ReactCompositeComponent.js:75)
    at ReactCompositeComponentWrapper._constructComponentWithoutOwner (ReactCompositeComponent.js:304)
    at ReactCompositeComponentWrapper._constructComponent (ReactCompositeComponent.js:279)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:187)
    at Object.mountComponent (ReactReconciler.js:45)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:236)
    at ReactDOMComponent._createContentMarkup (ReactDOMComponent.js:659)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:526)

I'm trying to follow the todo app example, which is running fine for me, but I can't figure out what I'm doing differently. It just seems that the relay context isn't getting passed to the components for some reason.

I'm using [email protected]

Browser entry point (browser.tsx):

import 'babel-polyfill'

import BrowserProtocol = require('farce/lib/BrowserProtocol')
import createInitialBrowserRouter
	= require('found/lib/createInitialBrowserRouter')
import * as React from 'react'
import * as ReactDOM from 'react-dom'

import { createResolver, historyMiddlewares, renderConfig, routeConfig }
	from './App'
import { ClientFetcher } from './fetcher'


(async () => {

	const fetcher = new ClientFetcher('http://localhost:3000/graphql',
	                                  window['__RELAY_PAYLOADS__'])
	const resolver = createResolver(fetcher)

	const Router = await createInitialBrowserRouter({
		historyProtocol: new BrowserProtocol(),
		historyMiddlewares,
		routeConfig,
		resolver,
		render: renderConfig,
	})

	ReactDOM.render(
		<Router resolver={resolver} />,
		document.getElementById('root')
	)

})()

Router/App File:

import queryMiddleware = require('farce/lib/queryMiddleware')
import createRender = require('found/lib/createRender')
import makeRouteConfig = require('found/lib/makeRouteConfig')
import Route = require('found/lib/Route')
import * as React from 'react'
const graphql = require('react-relay').graphql
import { Resolver } from 'found-relay'
import { Environment, Network, RecordSource, Store } from 'relay-runtime'

import RouteComponentProps from './props/RouteComponentProps'
import Main from './components/Main'
import VideoList from './components/VideoList'
import ErrorPage from './components/ErrorPage'


export class AppFrame extends React.Component<RouteComponentProps, any> {

	render() { return (
		<Main>
			{this.props.children}
		</Main>
	)}

}


export const historyMiddlewares = [queryMiddleware]


export function createResolver(fetcher) {
	const environment = new Environment({
		network: Network.create((...args) => fetcher.fetch(...args)),
		store: new Store(new RecordSource()),
	});

	return new Resolver(environment);
}


export const renderConfig = createRender({
	renderError: ({ error }) => { return (
		<AppFrame>
			<ErrorPage error={error}/>
		</AppFrame>
	) }
})


const ActiveVideosQuery = graphql`
	query App_ActiveVideos_Query {
		activeVideos {
			...VideoList_activeVideos
		}
	}
`

export const routeConfig = makeRouteConfig(
	<Route path="/" Component={AppFrame}>
		<Route Component={VideoList} query={ActiveVideosQuery} />
		{/*<Route Component={() => <h2>Video List</h2>} />*/}
		<Route path="videos/forms/replace" Component={() => <h2>Form</h2>} />
		<Route path="goomba" Component={() => <h2>Goomba</h2>} />
	</Route>,
)

VideoList component:

import * as React from 'react'
import * as Relay from 'react-relay'
const graphql = Relay.graphql

import Video from './Video'



interface VideoListProps {
	activeVideos: any[]
}


class VideoList extends React.Component<VideoListProps, any> {

	render() {
		const videos = this.props.activeVideos.map((vid) => { return (
			<Video key={vid.id} video={vid} />
		)})

		return (
			<section className="video-list">
				{ videos }
			</section>
		)
	}

}


export default Relay.createFragmentContainer(VideoList, graphql`
	fragment VideoList_activeVideos on Video @relay(plural: true) {
		id
		...Video_video
	}
`)

Allow hitting global renderPending

We should support render methods returning undefined, which will then cause things to hit the global renderPending, as in base Found.

This should be the default when specifying only Component and no render.

This might require/work best with removing prerender and just passing in an initialRender property to render to signify initial renders (when throwing Found errors would be allowed).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.