从Apollo商店检索数据

时间:2018-02-23 08:51:12

标签: javascript reactjs apollo react-apollo apollo-client

我创建了一个LoginMutation,它返回一个令牌和一个用户(带有他的id和firstName)。 这是变异模式:

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

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

enter image description here

我创建了一个Layout组件,我想在其上显示用户的firstName。那么如何从apollo商店获取数据呢?

感谢您的帮助。

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

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以将其传递给补充工具栏道具

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;

1 个答案:

答案 0 :(得分:2)

有两种选择。首先,我将解释我喜欢的解决方案,这非常简单,后来解决方案更简单。

首先,实现基本查询

供参考,文档非常好:Basic Queries

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

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选项。

您可以详细了解here

在您的情况下,变异操作应该类似于:

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以获取当前用户的数据。当您发现需要访问其他地方的用户数据时,这可能很麻烦。