Skip to content

Instantly share code, notes, and snippets.

@fdecampredon
Last active August 27, 2017 17:04
Show Gist options
  • Save fdecampredon/f337605e393a5b032b85 to your computer and use it in GitHub Desktop.
Save fdecampredon/f337605e393a5b032b85 to your computer and use it in GitHub Desktop.
redux-relay
import React from 'react';
import { container } from 'redux-relay';
@container({
variablesFromState: (state) => ({myVariable: state.myState})
fragments: {
Relay.QL`
viewer {
myFunc($myVariable) {
foo,
bar
}
}
`
}
});
class Container extends React.Component {
render() {
const { viewer } = this.props;
....
}
}
export default Container;
import Relay from 'react-relay';
import React from 'react';
import {Provider as ReactReduxProvider } from 'react-redux';
let store;
function setStore(value) {
store = value;
}
const containerProperties = {
'getFragmentNames': true,
'getQueryNames': true,
'hasFragment': true,
'hasVariable': true,
'getFragment': true,
'getQuery': true,
'contextTypes': false,
'displayName': false,
'moduleName': false
};
function createLazyContainer(Container, variablesFromState, fragments) {
let relayContainer;
const getRelayContainer = () => {
if (!relayContainer) {
const {forceFetch, ...initialVariables} = variablesFromState(store.getState()); //eslint-disable-line no-unused-vars
relayContainer = Relay.createContainer(Container, { initialVariables, fragments });
}
return relayContainer;
};
const lazyContainer = (props, context) => {
const Container = getRelayContainer();
return new Container(props, context);
};
for (let property of Object.keys(containerProperties)) {
const isFunction = containerProperties[property];
if (isFunction) {
Object.defineProperty(lazyContainer, property, {
value: function (...args) {
const container = getRelayContainer();
return container[property](...args);
},
enumerable: true,
configureable: true,
writable: true
});
} else {
Object.defineProperty(lazyContainer, property, {
get: () => getRelayContainer()[property],
set: (val) => getRelayContainer()[property] = val,
enumerable: true,
configureable: true
});
}
}
return lazyContainer;
}
export function container({variablesFromState, fragments}) {
return function (Component) {
if (variablesFromState) {
class Container extends React.Component {
static displayName = `ReduxRelay(${Component.displayName || Component.name})`
componentDidMount() {
this._subscription = store.subscribe(() => {
const { forceFetch, ...variables } = variablesFromState(store.getState());
if (forceFetch) {
this.props.relay.forceFetch(variables);
} else {
this.props.relay.setVariables(variables);
}
});
}
componentWillUnmount() {
this._subscription.dispose();
}
render() {
return <Component {...this.props} />;
}
}
return createLazyContainer(Container, variablesFromState, fragments);
} else {
return Relay.createContainer(Component, { fragments });
}
};
}
export const Provider = ({store, ...props}) => {
setStore(store);
return <ReactReduxProvider store={store} {...props} />;
};
import { Provider } from 'redux-relay';
import Relay from 'react-relay';
import ReactDOM from 'react-dom';
import configureStore from './store';
import Container from './Container';
import route from './route';
const store = configureStore();
ReactDOM.render(
<Provider store={store}>
<Relay.RootContainer route={route} Component={Container} />
</Provider>
);
@mvanlonden
Copy link

Thanks for putting this together! Just added babel-plugin-transform-decorators-legacy but now I'm getting TypeError: Cannot read property 'getState' of undefined (line 27 of redux-relay). It throws the error before the modified provider has a chance to add the state. It looks like it trying to get the state before runtime?

@amkoehler
Copy link

This is amazing. Thanks for sharing. I asked a question on stack overflow about how to accomplish this (http://stackoverflow.com/questions/41069179/retrieving-variables-for-a-relay-query-fragment-from-an-external-store) and answered my own question with a link to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment