在阿波罗中使用Refetch重新呈现查询和组件

时间:2018-06-29 23:14:09

标签: reactjs graphql apollo apollo-client

我在通过查询为组件补充新数据时遇到问题。为了设置前提,我有两个像这样的兄弟姐妹:

<Container>
 <Navbar />
 <Login /> || <Home />
</Container

基本上,在我的登录组件中,我有一个突变,当我点击登录时,运行如下:

this.props.mutate({
        variables: { token },
        refetchQueries: () =>  ['isAuthenticated']
    }).then((data) => {
      console.log(data);
      this.props.history.push(`/`);
    })

所以结果最终是什么也没有回报,我在导航组件中使用console.log()来查看其属性是否已更改,但是没有改变,但是在我的网络标签和缓存中应该返回的数据。

我的导航项组件如下:

import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import gql from "graphql-tag";
import { graphql, compose } from "react-apollo";
import { withStyles } from "@material-ui/core/styles";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Button from "@material-ui/core/Button";
import headerLinksStyle from "./HeaderLinksStyle";
import { LockOpen, GetApp, Info } from "@material-ui/icons";

const isLoggedInQuery = gql`
  query isLoggedInQuery {
    token @client
  }
`;

const loggedInMutation = gql`
  mutation authToken($token: String!) {
    assignAuthToken(token: $token) @client {
      token
    }
  }
`;

const userQuery = gql`
  query isAuthenticated {
    currentUser {
      id
      firstName
      lastName
      gender
      location
      password
      email
      permissions {
        id
        name
        displayOrder
        description
      }
      roles {
        id
        name
        description
        displayOrder
      }
    }
  }
`;

class HeaderLinks extends Component {
  logout = () => {
    localStorage.removeItem("auth_token");
    this.props.mutate({
      variables: { token: null }
    });
    this.props.history.push(`/`);
  };

  refetch = () => {
    console.log("refetch")
    this.props.user.refetch();
  }
  render() {
    const { classes } = this.props;
    const { token } = this.props.data;
    const isLoggedIn = token;
    console.log(this.props);
    return (
      <List className={classes.list}>
        {!isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Link to="/login" style={{ color: "inherit" }}>
              <Button color="inherit" className={classes.navLink}>
                <LockOpen className={classes.icon} />Login
              </Button>
            </Link>
          </ListItem>
        )}
        {!isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Link to="/signup" style={{ color: "inherit" }}>
              <Button color="inherit" className={classes.navLink}>
                <GetApp className={classes.icon} />Sign up
              </Button>
            </Link>
          </ListItem>
        )}
        <ListItem className={classes.listItem}>
            <Button color="inherit" className={classes.navLink} onClick={() => { this.refetch();}}>
              <Info className={classes.icon} />About
            </Button>
        </ListItem>
        {isLoggedIn && (
          <ListItem className={classes.listItem}>
            <Button
              color="inherit"
              className={classes.navLink}
              onClick={event => {
                this.logout();
              }}
            >
              <LockOpen className={classes.icon} />Logout
            </Button>
          </ListItem>
        )}
      </List>
    );
  }
}

export default compose(
  graphql(isLoggedInQuery),
  graphql(loggedInMutation),
  graphql(userQuery, { name: "user", options: {fetchPolicy: 'network-only'}}),
  withStyles(headerLinksStyle),
  withRouter
)(HeaderLinks);

解散this.props.user.refetch()可以正常工作,但是我的道具又返回了过时的信息/错误或数据。

2 个答案:

答案 0 :(得分:0)

这可能不会回答您有关重新获取查询的问题,但是在登录操作中使用client.resetStore()是一个好习惯。由于您可能希望在用户登录后重新获取缓存在Apollo Store中的所有结果。

这还应该解决依赖于查询数据的组件上的任何重新渲染问题。

仅当组件将这些查询结果作为道具接收时,组件才会重新渲染。

答案 1 :(得分:0)

您是否正在使用graphiql工具?您应该对在currentUser文件夹中导入的queries进行查询。您还应该在Logout文件夹中有一个mutations突变,并导入它。这样,您可以在HeaderLinks的末尾使用一个清洁的衬纸,如下所示:export default graphql(mutation)(graphql(query)(HeaderLinks));并且仅用于初学者。我建议像这样重构:

import React, { Component } from 'react';
import { graphql } from 'react-apollo';
import { Link } from 'react-router';
import query from '../queries/CurrentUser';
import mutation from '../mutations/Logout';

class HeaderLinks extends Component {
  onLogoutClick() {
    this.props.mutate({});
  }

  renderButtons() {
    const { loading, user } = this.props.data;
    if (loading) {
      return <div />;
    }
    if (user) {
      return (
        <li>
          <a onClick={this.onLogoutClick.bind(this)}>Logout</a>
        </li>
      );
    } else {
      return (
        <div>
          <li>
            <Link to="/signup">Signup</Link>
          </li>
          <li>
            <Link to="/login">Login</Link>
          </li>
        </div>
      );
    }
  }

  render() {
    return (
      <nav>
        <div className="nav-wrapper">
          <Link to="/" className="brand-logo left">
            Home
          </Link>
          <ul className="right">{this.renderButtons()}</ul>
        </div>
      </nav>
    );
  }
}

export default graphql(mutation)(graphql(query)(Header));

现在,上面假设要实现CSS样式化,您可能正在使用其他东西,这很好,只需反映一下即可,但是我认为我上面分享的内容更加简洁,可以帮助您。

因此,在运行突变后,我会说我希望GraphQL自动重新获取此查询列表,即使它只是一个查询,但是我要传递一个数组,因为那是帮助程序希望我这样做的原因:

class HeaderLinks extends Component {
  onLogoutClick() {
    this.props.mutate({
      refetchQueries: [{}]
    });
  }

所以我只有一个查询要重新运行,它是我导入为查询的currentUser查询,我将这样定义它:

class HeaderLinks extends Component {
  onLogoutClick() {
    this.props.mutate({
      refetchQueries: [{ query: query }]
    });
  }

键值具有相同的变量名,因此我们可以将其压缩为这样的查询:

class HeaderLinks extends Component {
  onLogoutClick() {
    this.props.mutate({
      refetchQueries: [{ query }]
    });
  }

因此,在运行变异后,请重新运行此查询并重新呈现与该查询关联的任何组件,并且标题应在屏幕上自动更新。