从 Apollo 商店检索数据

Retrieve data from Apollo store

我创建了一个 LoginMutation,其中 return 一个令牌和一个用户(带有他的 ID 和名字)。 这是突变模式:

const LOGIN_MUTATION = gql`
  mutation loginMutation($email: String!, $password: String!) {
    loginUser(email: $email, password: $password) {
      token
      user {
        id
        firstName
      }
    }
  }

当我在我的网站上输入令牌和用户时,graphql 服务器很好地 returned。用户已存储,我可以在我的开发工具中看到它:

我创建了一个布局组件,我想在其上显示用户的名字。那么如何从 apollo store 获取数据呢?

感谢您的帮助。

下面提供了与此问题有关的文件:

LoginPage.js

class LoginPage extends Component {

constructor(props) {
    super(props);
    this.state = {
        login: true, //switch between Login and SignUp
        email: '',
        password: '',
        firstName: '',
        lastName: '',
        loading: false,
        error: ''
    };
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
}

handleSubmit(){
    this.setState({loading: true, error: ''});
    this._confirm();
}

handleInputChange(event) {
    const target = event.target;
    const value = target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

render(){

    return (
            <div>
                <div>
                    {this.state.loading ? 
                    <CircularProgress size={60} thickness={7} /> :
                    this.state.login ? 
                        <LoginForm onSubmit={this.handleSubmit} onChange={this.handleInputChange}/> 
                        : 
                        <RegisterForm />
                    }
                </div>
                {this.state.error ? <div className="error">{this.state.error}</div> : ''}
                <a
                    onClick={() => this.setState({ login: !this.state.login })}
                >
                {this.state.loading ? 
                '' : this.state.login ? 
                        'Besoin d\'un compte ?' : 'Déjà un compte ?'
                }
                </a>
            </div>
    )
}

_confirm = ()  => {
  const { firstName, lastName, email, password } = this.state;
  if (this.state.login) {
    this.props.loginMutation({
      variables: {
        email,
        password,
      }
    })
    .then(({data}) => {
      this.setState({loading: false});
      const { token } = data.loginUser;
      this._saveUserData(token);
      checkAuth.authenticate();
    })
    .then(() => {
      this.props.history.push(`/`);
    }).catch((error) => {
      this.setState({loading: false, error: error});
    });
  }
}

   _saveUserData = (token) => {
    localStorage.setItem('token', token);
  }
}   

const LOGIN_MUTATION = gql`
    mutation loginMutation($email: String!, $password: String!) {
    loginUser(email: $email, password: $password) {
       token
       user {
        id
        firstName
       }
    }
 }
`

export default compose(graphql(LOGIN_MUTATION, { name: 'loginMutation' }))(LoginPage)

App.js页面之间的路由器

class App extends Component {
  constructor(props) {
      super(props);
  }

  render() {
    return (
      <div>
        <Switch>
          <Route exact path='/connexion' component={LoginPage} />
          <PrivateRoute exact path='/' component={WelcomePage} />
        </Switch>
      </div>
    )
  }
}

export default App;

Layout.js 我想从缓存中获取用户 firstName 以将其传递给 Sidebar props

class Layout extends Component {
    constructor(props) {
        super(props);
        this.state = {
            open: false,
        };
        this.logout = this.logout.bind(this);
    }

    logout() {
        this.props.client.resetStore();
        localStorage.removeItem('token');
        checkAuth.signout();
        this.props.history.push(`/`);
    }

    handleTouchMap() {
        this.setState({open: !this.state.open});
    }

    render() {
        return (
            <div>
                <AppBar title="myApp" iconElementRight={<RightMenu onDisconnect={ this.logout } />} onLeftIconButtonTouchTap = { this.handleTouchMap.bind(this) } />
                <Sidebar open={this.state.open} onRequestChange={(open) => this.setState({open})} firstName={this.props.firstName} />
                { this.props.children }
            </div>
        );
    }

}

export default withApollo(withRouter(Layout));

WelcomePage.js

class WelcomePage extends Component {
    render() {
        return (
            <div>
                <Layout>
                    <WelcomeComponent />
                </Layout>
            </div>
        );
    }
}

export default WelcomePage;

有2个选项。首先我会解释我喜欢的非常简单的解决方案,然后是更简单的解决方案。

首先,实现一个基本查询

在你的情况下它会是这样的:

const CURRENT_USER_QUERY = gql`
  query currentUserQuery {  
    user {
        id
        firstName
      }
   }`;

您可以像这样将其添加到 Layout 组件中:

export default compose(
  withApollo,
  graphql(CURRENT_USER_QUERY, { /* ... query configuration */ })
)(withRouter(Layout));

请注意,查询选项之一是 fetchPolicy。在这种特定情况下,您可能只需要 cache-only。开始时它应该足够了,但随着您添加更多字段,您可能需要考虑将其更改为更适合您的设计的内容。在这里您可以了解 Query Fetch Policies

现在这个查询仍然不会检索数据,因为它没有按查询预期的方式存储。这就引出了第二部分:

二、突变后更新缓存

为此,您需要在变异操作中使用 update 选项。

在你的例子中,变异操作应该类似于:

graphql(LOGIN_MUTATION, { name: 'loginMutation',
  update: (proxy, { data: { loginUser } }) => {      
    const data = { user: loginUser.user };
    proxy.writeQuery({ query: CURRENT_USER_QUERY, data });
  }
})

如果您看过文档中的示例,您会发现这里没有调用 proxy.readQuery,原因有两个。

  • 在此登录案例中,可以安全地假设 usernull。它可能与其他突变无关。
  • 如果您尝试读取的对象不在缓存中proxy.readQuery 将抛出异常

更简单的解决方案

它只需要您添加一个基本查询。

例如:

const USER_QUERY = gql`
  query userQuery($userId: ID) {
    user(id: $userId) {
        id
        firstName
      }
   }`;

// ...

export default compose(
  withApollo,
  graphql(USER_QUERY, { 
      variables: () => { 
        return { userId: /* get the user id, maybe from the local storage*/}; 
      }, 
      /* ... query configuration */ 
  }),
)(withRouter(Layout));

缺点,如您所见,您将始终需要存储并提供用户 ID 以获取当前用户的数据。当您发现需要访问其他地方的用户数据时,这可能会很麻烦。