Запрос Graphql выполняется только после обновления - PullRequest
0 голосов
/ 04 мая 2020

Я использую React, Graphql и Apollo.

Мой индекс. js выглядит следующим образом:

const client = new ApolloClient({
    uri: GRAPHQL_URL,
    fetchOptions: {
        credentials: 'include'
    },
    request: (operation) => {
        const token = localStorage.getItem(AUTH_TOKEN_KEY) || "";
        operation.setContext({
            headers: {
                Authorization: `JWT ${token}`
            }
        })
    },
    clientState: {
        defaults: {
            isLoggedIn: !!localStorage.getItem(AUTH_TOKEN_KEY)
        }
    }
});

const IS_LOGGED_IN_QUERY = gql`
    query {
        isLoggedIn @client
    }
`;

ReactDOM.render(
  <ApolloProvider client={client}>
    <Query query={IS_LOGGED_IN_QUERY}>
        {({data}) => {
            return data.isLoggedIn ? <App/> : <Login/>
        }}
    </Query>
  </ApolloProvider>,
  document.getElementById('root')
);

Таким образом, если пользователь вошел в систему, я сохраняю токен в localStorage и <App /> отображается вместо <Login />

<Login /> выглядит следующим образом:

const Login = () => {
    const [username, setUsername] = useState("");
    const [password, setPassword] = useState("");
    const [logIn, { loading: mutationLoading, error: mutationError }] = useMutation(LOG_IN_MUTATION);
    const client = useApolloClient();


    const handleSubmit = async (e) => {
        e.preventDefault();
        const res = await logIn({variables: {username, password}});
        client.writeData({ data: { isLoggedIn: true } })
        localStorage.setItem(AUTH_TOKEN_KEY, res.data.tokenAuth.token);
    };

    return ( ... )

В де <App /> я выполняю запрос Graphql к бэкэнду получить данные текущего пользователя. Этот застрявший код в бэкэнде работает должным образом.

<App /> выглядит следующим образом:

function App() {
    const {loading, error, data} = useQuery(GET_ME);

    if (loading) return <div><LoadingIndicator1/></div>
    if (!loading && error) return <div ><ErrorIndicator/></div>

    return (
        ...
    );
}

export default App;

И запрос GET_ME выглядит следующим образом:

export const GET_ME = gql`
    {
        me{
            id
            username
            firstName
            lastName
            email
        }
    }
`;

Функция для выхода из системы выглядит следующим образом:

const client = useApolloClient();

    const signOut = (client) => {
        localStorage.removeItem(AUTH_TOKEN_KEY);
        client.writeData({
            data: {
                isLoggedIn: false
            }
        })
    };

Но проблема в том, что когда я вхожу в систему с одним пользователем и выходом из системы, а затем вхожу с другим пользователем, я все еще вижу старого. Если я затем перефразирую sh, я вижу нового пользователя.

Есть идеи, что я делаю неправильно?

ОБНОВЛЕНИЕ

Компонент <App /> выглядит следующим образом:

function App() {
    const {loading, error, data} = useQuery(GET_ME);

    if (loading) return <div><LoadingIndicator1/></div>
    if (!loading && error) return <div ><ErrorIndicator/></div>

    return (
        <Router>
        <UserContext.Provider value={data.me}>
            <ToastProvider>
                <Header/>
                <Switch>
                    <Route path="/report/:id">
                        <NewReport/>
                    </Route>
                    <Route exact path="/report/">
                        <NewReport/>
                    </Route>
                    <Route path="/reports/">
                        <Reports/>
                    </Route>
                    <Route exact path="/">
                        <Home/>
                    </Route>
                </Switch>
            </ToastProvider>
        </UserContext.Provider>
    </Router>
    );
}

И компонент, в котором я использую данные пользователя, выглядит следующим образом:

render (
    <div>
        {localStorage.getItem(AUTH_TOKEN_KEY) !== null && <div>
                        <div className=''>
                           <span>{currentUser.username}</span>
                            <i className="fad fa-angle-down" />
                        </div>
                    </div>}
    </div>
)

1 Ответ

0 голосов
/ 05 мая 2020

Я делаю это в main component () и затем передаю через React Context всем дочерним компонентам.

Я хочу сделать это в одном месте и передать его как реквизит.

Использование контекста дублирует уже существующий контекст клиента apollo. Вы можете просто useQuery получить то же самое (cache-only, если хотите).

Другие подсказки:

  • 'основной' запрос (<Query query={IS_LOGGED_IN_QUERY}>) должен быть F C (с крючком useQuery) и объединены в компонент <App/>;
  • если определено me, то пользователь вошел в систему (ненужное дублирование состояния) - вы можете объединить их в одном запросе;
  • чаще аутентификация маршрутизатора / частные / защищенные маршруты ?
  • устаревшие методы (локальное состояние apollo, маршрутизатор)

Основная проблема

... возможно, вызвано кэшированными результатами запроса GET_ME. Он не network-only и не параметризован какой-либо переменной идентификатора пользователя.

Из документов Apollo ( auth ):

Самый простой способ убедиться, что пользовательский интерфейс и Состояние хранилища отражает права текущего пользователя на client.resetStore() после завершения процесса входа или выхода из системы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...