Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraphqlとReact

 GraphqlとReact

GraphqlとReactを組み合わせた場合のフレームワークの良し悪しとか紹介とか

More Decks by Taketoshi Aono(青野健利 a.k.a brn)

Other Decks in Programming

Transcript

  1. Relay import React from 'react'; import Relay from 'react-relay'; class

    App extends React.Component { render() { return ( <ul> {this.props.todos.todos.edges.map(edge => <li key={edge.node.id}>{edge.node.name} (ID: {edge.node.id})</li>)} </ul> ); } } Component
  2. Relay export default Relay.createContainer(App, { fragments: { todos: () =>

    Relay.QL` fragment on Todos { todos(first: 1) { edges { node { id value }, }, }, } `, }, }); Container
  3. Relay import Relay from 'react-relay'; export default class extends Relay.Route

    { static queries = { viewer: () => Relay.QL` query { todos } `, }; static routeName = 'AppHomeRoute'; } Route
  4. Relay import 'babel-polyfill'; import App from './components/App'; import AppHomeRoute from

    './routes/AppHomeRoute'; import React from 'react'; import ReactDOM from 'react-dom'; import Relay from 'react-relay'; ReactDOM.render( <Relay.Renderer environment={Relay.Store} Container={App} queryConfig={new AppHomeRoute()} />, document.getElementById('root') ); App
  5. Relay 今度こそ! Error : Invalid introspection data supplied to `getBabelRelayPlugin()`.

    The resulting schema is not an object with a `__schema` property or a schema IDL language. while parsing file…
  6. React-apollo import { ApolloClient, createNetworkInterface } from 'react- apollo'; export

    const client = new ApolloClient({ networkInterface: createNetworkInterface({ uri: 'http://localhost:3000/graphql' }) }); Client
  7. React-apollo import { gql, graphql } from 'react-apollo'; import React

    from 'react'; const QUERY = gql` query TodoAppQuery($id: ID) { todos(id: $id) { id text } }`; @graphql(QUERY, { options(props) { return {id: props.id} } }) export default class TodoApp extends React.Component { render() { const {fetchMore, refetch, todos = []} = this.props.data; return ( <div> <button onClick={() => refetch()}>Refresh</button> <ul>{todos.map(todo => <li key={todo.id}>{todo.text}</li>)}</ul> </div> ); } } Component
  8. React-apollo import { ApolloProvider } from 'react-apollo'; import ReactDOM from

    'react-dom'; import React from 'react'; import {client} from './client'; import TodoApp from './todo'; ReactDOM.render(( <ApolloProvider client={client}> <TodoApp id={null}/> </ApolloProvider> ), document.querySelector('#app')); App
  9. React-apollo import ApolloClient, { createNetworkInterface } from 'apollo-client’; const networkInterface

    = createNetworkInterface({ uri: '/graphql' }); networkInterface.use([{ applyMiddleware(req, next) { if (!req.options.headers) { req.options.headers = {}; // Create the header object if needed. } req.options.headers['authorization'] = localStorage.getItem('token') ? localStorage.getItem('token') : null; next(); } }]); const client = new ApolloClient({ networkInterface, }); App
  10. React-apollo data: { loading: false, error: null, variables: { id:

    'asdf' }, refetch() { ... }, fetchMore() { ... }, startPolling() { ... }, stopPolling() { ... }, // ... more methods } this.props.data配下に便利なメソッド、プロパティが定義される
  11. React-apollo+Redux import { gql, graphql } from 'react-apollo'; import {connect}

    from 'react-redux'; import React from 'react'; import {addTodo, getTodos} from './action'; @connect((state) => state, (dispatch) => ({ addTodo(todo) {return dispatch(addTodo(todo))}, getTodos(todo) {return dispatch(getTodos(todo))} })) @graphql(ADD_QUERY, { props({ownProps, mutate}) { return { addTodo(text) { mutate({variables: {text}}).then(t => ownProps.addTodo(t.data.addTodo)); } } } }) @graphql(QUERY, { options(props) { return {id: props.id}; }, skip: props => typeof window === 'object' }) export default class TodoApp extends React.Component { constructor(p, c) { super(p, c); } render() { const {todosRoot: {todos = []}, addTodo} = this.props; return ( <div> <div> <input type="text" onChange={e => this._handleInput(e)}/> <button onClick={() => addTodo(this._value)}>add</button> </div> <button onClick={() => this.props.apollo.refetch()}>Refresh</button> <ul>{todos.map(todo => <li key={todo.id}>{todo.text}</li>))}</ul> </div> ); } } Component
  12. React-apollo+Redux import { createStore, combineReducers, applyMiddleware, compose } from 'redux’;

    import {ApolloClient} from 'react-apollo'; import todoReducer from './reducer'; export default (client) => { return createStore( combineReducers({ todosRoot: todoReducer, apollo: client.reducer() }), typeof window === 'object'? window.__APOLLO_STATE__: {}, // initial state compose( applyMiddleware(client.middleware()), (typeof window === 'object' && typeof indow.__REDUX_DEVTOOLS_EXTENSION__ ! == 'undefined') ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f ) ); }; Store
  13. React-apollo SSR import 'isomorphic-fetch'; import fs from 'fs'; import express

    from 'express'; import ejs from 'ejs'; import React from 'react'; import TodoApp from '../client/src/todo.jsx'; import {client} from '../client/src/client'; import {renderToString} from 'react-dom/server'; import {ApolloProvider, getDataFromTree} from 'react-apollo'; const app = express(); const template = fs.readFileSync('./index.html', 'utf8'); const tree = <ApolloProvider client={client}><TodoApp id={1}/></ ApolloProvider>; app.get('/', (req, res) => { getDataFromTree(tree).then(v => { res.end(ejs.render(template, {dom: renderToString(tree)})); }); }); app.listen(3000);