relay-tools / found-relay Goto Github PK
View Code? Open in Web Editor NEWRelay integration for Found
License: MIT License
Relay integration for Found
License: MIT License
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.
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?
Hi,
Just one example to use it can be very useful :)
Thanks in advance
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.
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().
readyState.retry
readyState
when calling retry
(possibly only when retry
does not succeed synchronously)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?
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
.
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:
/myroute/:id
or /myroute?id=xyz
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?
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)
...
How to do authentication check globally after relay modern query fired?
i.e. this.props.viewer.user !== null
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
?
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.
Right now you have to pass query to the route to get relay env in context of component.
Why not pass it to simple (non relay) components also? It may be very useful to run mutations.
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.
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
}
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 HttpError
s and RedirectException
s?
@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?
I'm currently running into an issue where I'm doing a modal that involves capturing a previous instance of SnapshotRender.
<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.
QuerySubscription already has a listener.
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
<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.
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?
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!
@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.
When I switch from one route to another route, the same data is fetched again from server. is it normal?
I have an issue I don't understand with my current Relay app using found-relay.
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.
You need:
retry()
function given to the render function of the route.edit: Sorry early post. Updated with rest of issue
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.
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 ?
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.
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.
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
}
}
`;
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 } } }
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
}
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 ^^
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.
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
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!
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?
Something like what https://github.com/robrichard/relay-query-lookup-renderer is doing...
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)
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.
It seems the HOC of Relay gets in the way somehow and it is not working as in the given examples.
Hi,
I was wondering if they are any known issues with using found-relay and redux. When I do
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.
Hi.
Any plan to support Relay Modern?
I am big fan of found
,
and looking forward to use the new relay with it.
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:
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?
in [email protected] graphql result is a object:
but in relay modern SnapshotRenderer class render function match.route.query neet to be a function.
after change to the [email protected] it's ok
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.
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
}
`)
createFarceRouter
/&c. instead of createBrowserRouter
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).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.