代码之家  ›  专栏  ›  技术社区  ›  jkdowdle

阿波罗反应:阿波罗缓存持久化似乎不起作用

  •  0
  • jkdowdle  · 技术社区  · 6 年前

    也许我误解了这个包的作用,但我认为它可以读取缓存的响应,并有助于脱机应用程序的功能。

    import React from 'react'
    import { graphql } from 'react-apollo'
    import gql from 'graphql-tag'
    
    export const DATA_QUERY = gql`
        query Data {
            me {
                name
                bestFriend {
                    name
                }
            }
        }
    `
    
    const options = () => ({
      fetchPolicy: 'cache-only'
    })
    
    const withData = graphql(DATA_QUERY, { options })
    
    export const Start = ({ data }) =>
        data.loading ? (
            'loading!'
        ) : data.me ? (
            <div>
          {console.log('data', data)}
                <h3>Me: {data.me.name}</h3>
                <p>Best friend: {data.me.bestFriend.name}</p>
            </div>
        ) : (
            'no data'
        )
    
    export default withData(Start)
    
    // index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import registerServiceWorker from './registerServiceWorker';
    import { ApolloProvider } from 'react-apollo'
    import { ApolloClient } from 'apollo-client'
    import { InMemoryCache } from 'apollo-cache-inmemory'
    import { HttpLink } from 'apollo-link-http'
    import { persistCache } from 'apollo-cache-persist'
    
    const cache = new InMemoryCache()
    
    persistCache({
      cache,
      storage: window.localStorage,
      debug: true
    })
    
    export const client = new ApolloClient({
      link: new HttpLink({ uri: 'https://v9zqq45l3.lp.gql.zone/graphql' }),
      cache
    })
    
    ReactDOM.render(
      <ApolloProvider client={client}>
        <App />
      </ApolloProvider>,
    document.getElementById('root'));
    registerServiceWorker();
    

    我的本地存储中确实有缓存

    apollo-cache-persist: "{"$ROOT_QUERY.me":{"name":"Bob","bestFriend":{"type":"id","id`enter code here`":"$ROOT_QUERY.me.bestFriend","generated":true}"
    

    使用fetchPolicy运行上述示例时:“仅缓存”组件呈现“无数据”。如果我执行默认的fetchPolicy,即先缓存,那么我会得到预期的结果,但我可以看到正在发出网络请求。

    编辑:现在与Daniels answer一起使用,此解决方法在运行查询之前等待恢复缓存。

    import Start from './Start'
    
    class App extends Component {
      state = {
        show: false
      }
    
      toggle = () =>
        this.setState({ show: !this.state.show })
    
      render() {
        return (
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <h1 className="App-title">Welcome to React</h1>
            </header>
            <br/><br/>
            <button onClick={this.toggle}>Show it</button>
            <br/><br/>
            {this.state.show && <Start />}
          </div>
        );
      }
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Daniel Rearden    6 年前

    为了正确缓存并稍后从缓存中检索数据,Apollo需要 id (或 _id )与一起工作。如果要使用其他属性作为id(如 name ),可以将dataIdFromObject函数传递给内存缓存的配置:

    const cache = new InMemoryCache({
      dataIdFromObject: object => {
        switch (object.__typename) {
          //User is whatever type "me" query resolves to
          case 'User': return object.name;
          default: return object.id || object._id;
        }
      }
    });
    
        2
  •  0
  •   jkdowdle    6 年前

    像这样的方法是可行的,不过我想知道是否应该有一个更优雅的解决方案。可能是重试链接。

    https://github.com/apollographql/apollo-cache-persist/issues?utf8=%E2%9C%93&q=is%3Aissue+

    export class Index extends Component {
        state = {
            client: null
        }
    
        async componentWillMount() {
            const httpLink = new HttpLink({ uri: 'https://v9zqq45l3.lp.gql.zone/graphql' })
    
            const link = ApolloLink.from([ httpLink ])
    
            const cache = new InMemoryCache({
                dataIdFromObject: (object) => {
                    switch (object.__typename) {
                        // User is whatever type "me" query resolves to
                        case 'User':
                            return object.name
                        default:
                            return object.id || object._id
                    }
                }
            })
    
            await persistCache({
                cache,
                storage: window.localStorage,
                debug: true
            })
    
            const client = new ApolloClient({
                link,
                cache
        })
    
        this.setState({ client })
        }
    
        render() {
            return !this.state.client ? (
                null
            ) : (
                <ApolloProvider client={this.state.client}>
                    <App />
                </ApolloProvider>
            )
        }
    }
    
    ReactDOM.render(<Index />, document.getElementById('root'))