2017-06-21 17 views
6

Tôi mới sử dụng graphql với phản ứng-appollo Tôi muốn sử dụng phản ứng apollo với redux cũng hiển thị phía máy chủ Mọi thứ đều ổn mà ứng dụng của tôi đang hoạt động nhưng vấn đề là khi ứng dụng của tôi render nó thực sự nhớ lại api một lần nữa sử dụng nhà nước trả lại tôi ..Làm thế nào để tránh tìm nạp lại khách hàng trong SSR phản ứng-apollo với redux?

enter image description here

máy chủ .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) 

Trả lời

1

Tôi có thể khẳng định rằng tôi hiểu được vấn đề một cách chính xác?

Bạn đang hiển thị phía máy chủ HTML.

  • HTML (Bao gồm tất cả các bài đăng) trong HTML được trả về trình duyệt.
  • Phản ứng sau đó thay đổi này đến cửa sổ tải
  • Phản ứng sau đó làm cho các cuộc gọi API, và ám chỉ rằng bài viết mới

LƯU Ý: Apollo sẽ luôn thực hiện cuộc gọi AJAX vì điều này được thực hiện tự động như một phần của ContainerWithData.

Giải pháp Hiển thị Cửa hàng Redux bằng tất cả dữ liệu. Ví dụ: khi thực hiện cuộc gọi đến "createStore", bạn hiện đang chuyển vào một đối tượng trống. Nếu bạn thực hiện cuộc gọi AJAX ở đây, bạn có thể điền trình duyệt/lưu trữ redux với tất cả dữ liệu cần thiết.

Tại thời điểm này, bạn có thể xóa cuộc gọi đến GraphQL trong vùng chứa. Bạn sẽ thay thế điều này bằng một số logic với "componentWillMount".

Logic sẽ là:

  • Tạo cửa hàng sử dụng mô hình dữ liệu trả về từ API
  • Gọi Home Component
  • Home chạy "componentWillMount"
  • kiểm tra componentWillMount nếu store.posts có dữ liệu
    • sau đó tải dữ liệu từ API (GraphQL)
    • người khác trả lại đúng sự thật và tiếp tục hiển thị
+0

Bạn có thể cung cấp một số ví dụ về mã .ill cung cấp cho bạn dữ liệu bạn muốn. – Nane

Các vấn đề liên quan