React-admin:登录后 useQuery 未在仪表板上获取数据
React-admin: useQuery not fetching data on Dashboard after logging in
我已经使用 GraphQL 设置了 react-admin 并且在大多数情况下工作正常......但是最初登录并让 Dashboard
进行查询似乎有问题;问题是它不会在初始加载时解决。它从登录 -> 仪表板开始,我遇到了一个永远加载的组件,没有 data
或 errors
.
我的Admin
是这样设置的:
const routes = [
<Route exact path="/support-chat-list" component={SupportChatPage} noLayout />,
<Route exact path="/group-chat" component={GroupChatPage} noLayout />,
<Route exact path="/" component={Dashboard} />,
];
const App = () => (
<Admin dashboard={Dashboard} layout={MyLayout} customRoutes={routes} dataProvider={dataProvider} authProvider={authProvider} i18nProvider={i18nProvider}>
{/* my resources... */}
</Admin>
);
我的 Dashboard
看起来像这样:
const requestOptions = (startingAfter, startingBefore) => {
return {
type : 'getList',
resource: 'appointments',
payload : {
pagination: {
perPage: 100,
page : 0,
},
sort : {
field: 'start_at',
order: 'asc'
},
filter : {
startingAfter: startingAfter.toString(),
startingBefore: startingBefore.toString(),
}
}
};
};
const handleSelectEvent = (event, e, redirectTo) => {
redirectTo('show', ROUTES.APPOINTMENTS, event.resource.id);
};
const initialState = {
middleDate: DateTime.local().startOf('day'),
startDate: DateTime.local().minus({days: 3}).startOf('day'),
endDate: DateTime.local().plus({days: 3}).endOf('day'),
};
export function Dashboard() {
useAuthenticated();
const redirectTo = useRedirect();
const [dateRanges, setDateRanges] = useState(initialState);
const {data, loading, error} = useQueryWithStore(requestOptions(dateRanges.startDate, dateRanges.endDate));
if (error) return <Error />;
return (
<Card>
<Title title="Admin" />
<CardContent>
{loading && <Loading/>}
{!loading &&
<Calendar
events={translateAppointmentData(data)}
//.......
我试过 useQuery
和 useQueryWithStore
但似乎没有任何效果。 它只会在我刷新页面时解决,然后才会加载所有内容。
我怀疑这与我的 authProvider
有关,这是一个处理身份验证的 class。有点臃肿所以我会尽力展示与login
相关的东西:
async login({username, password}) {
const response = await authClient.passwordGrant(username, password, ACCESS_TOKEN_SCOPES);
await this.processTokenResponse(response);
return Promise.resolve();
}
authClient.passwordGrant
看起来像这样:
passwordGrant(username, password, scopes) {
const request = new Request(`${this.url}/oauth/access_token`, {
method: 'POST',
body: JSON.stringify({
username: username,
password: password,
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: 'password',
scope: scopes.join(' '),
}),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
});
}
而 processTokenResponse
看起来像这样:
processTokenResponse(response) {
const now = DateTime.local();
localStorage.setItem(TOKEN_STORAGE_KEY, response.access_token);
localStorage.setItem(TOKEN_EXPIRY_STORAGE_KEY, now.plus({seconds: response.expires_in - EXPIRY_BUFFER}).toString());
localStorage.setItem(SCOPES_STORAGE_KEY, JSON.stringify({scopes: response.scopes}));
localStorage.setItem(REFRESH_TOKEN_STORAGE_KEY, response.refresh_token);
localStorage.setItem(REFRESH_TOKEN_EXPIRY_STORAGE_KEY, now.plus({seconds: response.refresh_token_expires_in - EXPIRY_BUFFER}).toString());
return this.fetchActiveUserData();
}
和 fetchActiveUserData
看起来像这样:
async fetchActiveUserData() {
let dataProvider = new ActiveUserDataProvider();
return await dataProvider.getOne({}).then((response) => {
return this.processLoadUserResponse(response.data);
})
}
其中我的 dataProvider 如下所示:
import apolloClient from '../apolloClient';
import { BaseResourceDataProvider } from './baseResourceDataProvider';
import {FetchMeQuery} from "../graphql/users";
const FetchMeQuery = gql`
query FetchMe {
me {
id
firstName
lastName
name
username
timezone
}
}
`;
class ActiveUserDataProvider extends BaseResourceDataProvider {
getOne({ id }: { id?: string }) { // maybe something wrong here?
return apolloClient.query({
query: FetchMeQuery,
fetchPolicy: 'cache-first'
}).then((result) => {
return {
data: result.data.me,
};
});
}
}
我为这么长的时间道歉 post 但我完全不明白为什么我的 Dashboard
在最初登录后不查询数据,并且需要刷新才能工作。我希望有人能指出哪里出了问题。谢谢。
经过大量挖掘,结果证明这是我设置 ApolloClient 的方式。之前我使用 Apollo Link 设置我的 auth 中间件,发现它根本没有调用中间件。
我发现了 并用 setContext
替换了 ApolloLink 并且效果很好。这是现在的代码:
const authMiddleware = setContext(async (_, { headers }) => {
const token = await authProvider.checkAuth();
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
}
}
});
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: from([
authMiddleware,
httpLink
]),
});
我已经使用 GraphQL 设置了 react-admin 并且在大多数情况下工作正常......但是最初登录并让 Dashboard
进行查询似乎有问题;问题是它不会在初始加载时解决。它从登录 -> 仪表板开始,我遇到了一个永远加载的组件,没有 data
或 errors
.
我的Admin
是这样设置的:
const routes = [
<Route exact path="/support-chat-list" component={SupportChatPage} noLayout />,
<Route exact path="/group-chat" component={GroupChatPage} noLayout />,
<Route exact path="/" component={Dashboard} />,
];
const App = () => (
<Admin dashboard={Dashboard} layout={MyLayout} customRoutes={routes} dataProvider={dataProvider} authProvider={authProvider} i18nProvider={i18nProvider}>
{/* my resources... */}
</Admin>
);
我的 Dashboard
看起来像这样:
const requestOptions = (startingAfter, startingBefore) => {
return {
type : 'getList',
resource: 'appointments',
payload : {
pagination: {
perPage: 100,
page : 0,
},
sort : {
field: 'start_at',
order: 'asc'
},
filter : {
startingAfter: startingAfter.toString(),
startingBefore: startingBefore.toString(),
}
}
};
};
const handleSelectEvent = (event, e, redirectTo) => {
redirectTo('show', ROUTES.APPOINTMENTS, event.resource.id);
};
const initialState = {
middleDate: DateTime.local().startOf('day'),
startDate: DateTime.local().minus({days: 3}).startOf('day'),
endDate: DateTime.local().plus({days: 3}).endOf('day'),
};
export function Dashboard() {
useAuthenticated();
const redirectTo = useRedirect();
const [dateRanges, setDateRanges] = useState(initialState);
const {data, loading, error} = useQueryWithStore(requestOptions(dateRanges.startDate, dateRanges.endDate));
if (error) return <Error />;
return (
<Card>
<Title title="Admin" />
<CardContent>
{loading && <Loading/>}
{!loading &&
<Calendar
events={translateAppointmentData(data)}
//.......
我试过 useQuery
和 useQueryWithStore
但似乎没有任何效果。 它只会在我刷新页面时解决,然后才会加载所有内容。
我怀疑这与我的 authProvider
有关,这是一个处理身份验证的 class。有点臃肿所以我会尽力展示与login
相关的东西:
async login({username, password}) {
const response = await authClient.passwordGrant(username, password, ACCESS_TOKEN_SCOPES);
await this.processTokenResponse(response);
return Promise.resolve();
}
authClient.passwordGrant
看起来像这样:
passwordGrant(username, password, scopes) {
const request = new Request(`${this.url}/oauth/access_token`, {
method: 'POST',
body: JSON.stringify({
username: username,
password: password,
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: 'password',
scope: scopes.join(' '),
}),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
});
}
而 processTokenResponse
看起来像这样:
processTokenResponse(response) {
const now = DateTime.local();
localStorage.setItem(TOKEN_STORAGE_KEY, response.access_token);
localStorage.setItem(TOKEN_EXPIRY_STORAGE_KEY, now.plus({seconds: response.expires_in - EXPIRY_BUFFER}).toString());
localStorage.setItem(SCOPES_STORAGE_KEY, JSON.stringify({scopes: response.scopes}));
localStorage.setItem(REFRESH_TOKEN_STORAGE_KEY, response.refresh_token);
localStorage.setItem(REFRESH_TOKEN_EXPIRY_STORAGE_KEY, now.plus({seconds: response.refresh_token_expires_in - EXPIRY_BUFFER}).toString());
return this.fetchActiveUserData();
}
和 fetchActiveUserData
看起来像这样:
async fetchActiveUserData() {
let dataProvider = new ActiveUserDataProvider();
return await dataProvider.getOne({}).then((response) => {
return this.processLoadUserResponse(response.data);
})
}
其中我的 dataProvider 如下所示:
import apolloClient from '../apolloClient';
import { BaseResourceDataProvider } from './baseResourceDataProvider';
import {FetchMeQuery} from "../graphql/users";
const FetchMeQuery = gql`
query FetchMe {
me {
id
firstName
lastName
name
username
timezone
}
}
`;
class ActiveUserDataProvider extends BaseResourceDataProvider {
getOne({ id }: { id?: string }) { // maybe something wrong here?
return apolloClient.query({
query: FetchMeQuery,
fetchPolicy: 'cache-first'
}).then((result) => {
return {
data: result.data.me,
};
});
}
}
我为这么长的时间道歉 post 但我完全不明白为什么我的 Dashboard
在最初登录后不查询数据,并且需要刷新才能工作。我希望有人能指出哪里出了问题。谢谢。
经过大量挖掘,结果证明这是我设置 ApolloClient 的方式。之前我使用 Apollo Link 设置我的 auth 中间件,发现它根本没有调用中间件。
我发现了 setContext
替换了 ApolloLink 并且效果很好。这是现在的代码:
const authMiddleware = setContext(async (_, { headers }) => {
const token = await authProvider.checkAuth();
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
}
}
});
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: from([
authMiddleware,
httpLink
]),
});