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

GraphqlとReact

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

 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);