从 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
,原因有两个。
- 在此登录案例中,可以安全地假设
user
是 null
。它可能与其他突变无关。
- 如果您尝试读取的对象不在缓存中,
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 以获取当前用户的数据。当您发现需要访问其他地方的用户数据时,这可能会很麻烦。
我创建了一个 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
,原因有两个。
- 在此登录案例中,可以安全地假设
user
是null
。它可能与其他突变无关。 - 如果您尝试读取的对象不在缓存中,
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 以获取当前用户的数据。当您发现需要访问其他地方的用户数据时,这可能会很麻烦。