How to avoid re-fetching customers in the response ASOLL by reducing?

I am new to Graphql with responsive-appollo. I would like to use apollo reaction with reduction and server side rendering. Every thing is in order, my application works, but the problem is that my application renders it, actually calls the api again, this is not using my displayed state.

enter image description here

server.js

import express from 'express'; import bodyParser from 'body-parser'; import path from 'path'; import expressGraphQL from 'express-graphql'; import schema from './GraphQL/Schema'; import React from 'react'; import ReactDOMServer from 'react-dom/server' import { StaticRouter } from 'react-router'; import { ApolloClient, createNetworkInterface, ApolloProvider } from 'react-apollo'; import { getDataFromTree } from "react-apollo" import store from '../client/Redux/Store/store'; import {serverClient} from './lib/apollo' require('es6-promise').polyfill(); require('isomorphic-fetch'); import WApp from '../client/App'; //Dev HMR import HMR from './serverUtils/HMR'; const app = express(); app.use(bodyParser.json()); app.use('/api', expressGraphQL({ schema, graphiql: true })); app.use('/static',express.static('build')); HMR(app); function Html({ content, state }) { return ( <html> <body> <div id="app" dangerouslySetInnerHTML={{ __html: content }}/> <script src="/static/app.js" /> <script dangerouslySetInnerHTML={{ __html: `window.__APOLLO_STATE__=${JSON.stringify(state).replace(/</g, '\\u003c')};`, }} /> </body> </html> ); } function createReactHandler(req) { return async function reactHandler(ctx) { const routeContext = {}; const client = serverClient(); const components = ( <StaticRouter location={req.url} context={routeContext}> <ApolloProvider store={store} client={client}> <WApp /> </ApolloProvider> </StaticRouter> ); await getDataFromTree(components); // const html = ReactDOMServer.renderToString(components); // // Handle redirects // if ([301, 302].includes(routeContext.status)) { // // 301 = permanent redirect, 302 = temporary // ctx.status = routeContext.status; // // // Issue the new `Location:` header // ctx.redirect(routeContext.url); // // // Return early -- no need to set a response body // return; // } // // // Handle 404 Not Found // if (routeContext.status === 404) { // // By default, just set the status code to 404. You can add your // // own custom logic here, if you want to redirect to a permanent // // 404 route or set a different response on `ctx.body` // ctx.status = routeContext.status; // } // return html; // console.log(html) } } const HTML = ({ html,state}) => ( <html lang="en" prefix="og: http://ogp.me/ns#"> <head> <meta charSet="utf-8" /> <meta httpEquiv="X-UA-Compatible" content="IE=edge" /> <meta httpEquiv="Content-Language" content="en" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <div id="app" dangerouslySetInnerHTML={{ __html: html }} /> <script dangerouslySetInnerHTML={{ __html: `window.__STATE__=${JSON.stringify(state)};`, }} /> <script src="/static/app.js" /> </body> </html> ); app.get('/*',(req,res) => { const routeContext = {}; const client = serverClient(); const components = ( <StaticRouter location={req.url} context={routeContext}> <ApolloProvider store={store} client={client}> <WApp /> </ApolloProvider> </StaticRouter> ); getDataFromTree(components).then(() => { const html = ReactDOMServer.renderToString(components); const initialState = {apollo: client.getInitialState()} console.log(client); res.send(`<!DOCTYPE html>\n${ReactDOMServer.renderToStaticMarkup( <HTML html={html} state={initialState} />, )}`) }) }) app.listen(3000,() => { console.log('Man I on') }) 

store.js

 import { createStore, compose, applyMiddleware } from 'redux'; import { syncHistoryWithStore } from 'react-router-redux'; import thunk from 'redux-thunk'; import {createLogger} from 'redux-logger'; import client from '../apolloClient'; import rootReducer from '../Reducers' //All Reducer import {initialState as allPosts} from '../Reducers/AllPosts_Reucer'; const isProduction = process.env.NODE_ENV !== 'development'; const isClient = typeof document !== 'undefined'; const initialState = { allPosts }; const middlewares = [thunk, client.middleware()]; const enhancers = []; if (!isProduction && isClient) { const loggerMiddleware = createLogger(); middlewares.push(loggerMiddleware); if (typeof devToolsExtension === 'function') { const devToolsExtension = window.devToolsExtension; enhancers.push(devToolsExtension()); } } const composedEnhancers = compose( applyMiddleware(...middlewares), ...enhancers ); const store = createStore( rootReducer, {}, composedEnhancers, ); export default store; 

apolloClient.js

 import ApolloClient, { createNetworkInterface, } from 'apollo-client'; const isProduction = process.env.NODE_ENV !== 'development'; const testUrl = 'http://localhost:3000/api'; // const url = isProduction ? productionUrl : testUrl; const url = testUrl; const client = new ApolloClient({ networkInterface: createNetworkInterface({uri:testUrl}), dataIdFromObject:({id}) => id, initialState: (typeof window !=='undefined')? window.__STATE__:{}, reduxRootSelector:state => state.custom }); export default client; 

Home.js

 import React,{Component} from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { graphql } from 'react-apollo'; import gql from 'graphql-tag'; import * as postActions from '../../Redux/Actions/postActions'; class Home extends Component{ componentWillMount(){ // console.log('From Will Mount',this.props.posts) } renderAllPost(){ const {loading,posts} = this.props; if(!loading){ return posts.map(data => { return <li key={data.id}>{data.title}</li> }) }else{ return <div>loading</div> } } render(){ return( <div> {this.renderAllPost()} </div> ) } } //start from here const GetallPosts = gql` query getAllPosts{ posts{ id title body } } `; const mapDispatchToProps = (dispatch) => ({ actions:bindActionCreators( postActions, dispatch ) }); const ContainerWithData = graphql(GetallPosts,{ props:({ data:{loading,posts} }) => ({ posts, loading, }) })(Home) export default connect( // mapStateToPros, // mapDispatchToProps )(ContainerWithData) 
+5
source share
1 answer

Can I confirm that I understood the problem correctly?

You are creating an HTML server server.

  • HTML (including all posts) is in the HTML returned to the browser.
  • React will then change this to the boot window.
  • It then responds to an API call and creates new messages.

NOTE. Apollo will always make an AJAX call, as it runs automatically as part of ContainerWithData.

Solution Provide a Redux repository with all the data. For example, when you call "createStore", you are currently passing an empty object. If you are making an AJAX call here, you can fill the browser / rework store with all the necessary data.

At this point, you can remove the GraphQL call in the container. You would replace this with some "componentWillMount" logic.

The logic will be:

  • Create a repository using model data returned from the API
  • Call home component
  • Home launches "componentWillMount"
  • componentWillMount checks for store.posts data
    • then load the data from the API (GraphQL)
    • else returns true and continues rendering
+1
source

Source: https://habr.com/ru/post/1269055/


All Articles