【问题标题】:Apollo Store Share State Between ComponentsApollo Store 在组件之间共享状态
【发布时间】:2019-02-18 09:14:16
【问题描述】:

我有一个标头,可以在显示Login/Signup 链接和Logout 状态之间切换,具体取决于它是否可以查询用户对象(基本上表明标头中是否有 jwt)。

这是我卡住的地方:在页面加载时,Header 组件获取用户信息,如果它返回数据,那么我知道要显示Login/Signup 链接。

所以,我点击登录链接,填写表格并成功登录。我想要发生的是触发 Header 重新获取用户信息。理想情况下,它会从登录返回的用户信息中检查本地缓存。

我已经习惯了 Redux 的思维框架,所以我觉得我缺少一些关于 Apollo 状态管理的基本知识。

以下是代码示例: Header.js

const USER_QUERY = gql`
  {
    user {
      id
      email
    }
  }
`;

const LOGOUT_MUTATION = gql`
  mutation LogoutMutation {
    logout {
      message
    }
  }
`;

const Header = () => (
  <div className="header">
    header

    <Query query={USER_QUERY}>
      {({ loading, error, data }) => {
        if (loading) return <div>Fetching</div>;
        if (error) {
          return (
            <div>
              <Link to="signup">Signup</Link>
              <Link to="login">Login</Link>
            </div>
          );
        }

        return (
          <div>
            {data.user.email}
            <Mutation
              mutation={LOGOUT_MUTATION}
            >
              {
                mutation => <button type="submit" onClick={mutation}>Logout</button>
              }
            </Mutation>
          </div>
        );
      }}
    </Query>

  </div>
);

Auth.js

const SIGNUP_MUTATION = gql`
  mutation SignupMutation($name: String!, $email: String!, $password: String!) {
    signup(name: $name, email: $email, password: $password) {
      id
      name
      email
    }
  }
`;

const LOGIN_MUTATION = gql`
  mutation LoginMutation($email: String!, $password: String!) {
    login(email: $email, password: $password) {
      id
      name
      email
    }
  }
`;

class Auth extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      email: '',
      password: '',
      name: '',
      isSignup: props.type === 'SIGNUP',
    };
  }

  render() {
    const {
      email,
      password,
      name,
      isSignup,
    } = this.state;

    return (
      <div>
        <h1>{isSignup ? 'Sign Up' : 'Log In'}</h1>

        <Mutation
          mutation={isSignup ? SIGNUP_MUTATION : LOGIN_MUTATION}
          variables={isSignup ? { name, email, password } : { email, password }}
          onCompleted={(res) => { console.log('complete', res); }}
        >
          {
            (mutation, { error }) => (
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  mutation();
                }}
              >
                {
                  isSignup
                  && (
                    <React.Fragment>
                      <label htmlFor="auth-name">name</label>
                      <input
                        value={name}
                        onChange={e => this.setState({ name: e.target.value })}
                        type="text"
                        placeholder="name"
                        id="auth-name"
                      />
                    </React.Fragment>
                  )
                }
                <label htmlFor="email">email</label>
                <input
                  value={email}
                  onChange={e => this.setState({ email: e.target.value })}
                  type="text"
                  placeholder="email"
                  id="auth-email"
                />

                <label htmlFor="password">password</label>
                <input
                  value={password}
                  onChange={e => this.setState({ password: e.target.value })}
                  type="password"
                  placeholder="password"
                  id="auth-password"
                />

                <button type="submit">Submit</button>
                { error && <div>ERROR Authenticating</div>}
              </form>
            )
          }
        </Mutation>
      </div>
    );
  }
}

【问题讨论】:

    标签: reactjs graphql apollo apollo-client


    【解决方案1】:

    在您的Header 组件中,您不应使用Query 组件的error 参数来检测用户是否登录。此参数用于处理graphql 错误、服务器错误和应该不是应用程序中的“正常”执行路径

    现在,您必须在尝试查询“isLoggedIn”状态之前决定如何处理它。

    据我了解,您决定将“isLoggedIn”状态存储在 url 中。换句话说,告诉您用户是否登录的唯一真实来源是 URL。

    从那里,您有各种存储选项,每个选项都有优点和缺点,我不会在这里讨论:

    • 保留在网址中
    • 将其存储在本地存储中
    • 使用 jwt cookie
    • 使用React Context
    • 使用apollo-link-state
    • ...任何其他将成为“事实来源”的存储选项

    【讨论】:

    • 我不确定 URL 中的登录状态是什么意思,但我有一个 httpOnly 安全 JWT cookie,标题中有用户 ID。但是,客户端需要一种方法来测试用户是否已登录,因此我向后端发送了一个已登录用户的查询。
    • 是的,这正是你不应该做的:) 你需要测试用户是否使用不涉及查询错误路径的另一种方法登录
    • 酷,是的,但这就是我正在努力解决的问题。那是什么测试?以及应用程序如何在全局范围内知道该测试是通过还是失败?
    • 您首先需要定义此状态(此数据)的单一事实来源。如果您想将其保留在 url 中,测试可能类似于 const isLoggedIn = doesURLHaveValidJWT()
    猜你喜欢
    • 1970-01-01
    • 2019-01-31
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    • 2010-11-12
    相关资源
    最近更新 更多