How to convert the data retrieved by GraphQL + Relay to normal React state?

How to convert the data retrieved by GraphQL + Relay to normal React state?


0

Example from the documentation:

import type {AppQueryType} from 'AppQueryType.graphql';

const React = require('React');

const {graphql, useQueryLoader, usePreloadedQuery} = require('react-relay');

const AppQuery = graphql`
  query AppQuery($id: ID!) {
    user(id: $id) {
      name
    }
  }
`;

type Props = {
  initialQueryRef: PreloadedQuery<AppQueryType>,
};

function NameLoader(props) {
  const [queryReference, loadQuery] = useQueryLoader(
    AppQuery,
    props.initialQueryRef, /* e.g. provided by router */
  );

  return (<>
    <Button
      onClick={() => loadQuery({id: '4'})}
      disabled={queryReference != null}
    >
      Reveal your name!
    </Button>
    <Suspense fallback="Loading...">
      {queryReference != null
        ? <NameDisplay queryReference={queryReference} />
        : null
      }
    </Suspense>
  </>);
}

function NameDisplay({ queryReference }) {
  const data = usePreloadedQuery(AppQuery, queryReference);

  return <h1>{data.user?.name}</h1>;
}

Too complicated. First, I don’t want to split the initial component to NameLoader and NameDisplay only because it is convenient for the Relay. Second, even I have the child component, I don’t want the PreloadedQuery be among props because it is the tight copulation of the Relay and the simple React component (it means the replacing of the Relay with something else will entail the editing of all components such NameDisplay). Instead I want to pass the normal data via props, such the user object.

The desired code will be like:

import type {AppQueryType} from 'AppQueryType.graphql';

const React = require('React');

const {graphql, useQueryLoader, usePreloadedQuery} = require('react-relay');

const AppQuery = graphql`
  query AppQuery($id: ID!) {
    user(id: $id) {
      name
    }
  }
`;


function NameLoader(props) {
  const rawUser = useMagic(AppQuery);
  const [ user, setUser ] = toLocalState(rawUser);

  return (<>
    <Button
      onClick={() => loadQuery({id: '4'})}
      disabled={queryReference != null}
    >
      Reveal your name!
    </Button>
    <h1>{user.name}</h1>;
  </>);
}

I understand that the data fetching is the asynchronous but it sould not mean that what Realy suggesting in the only correct solution.

From the const [ user, setUser ] = toLocalState(rawUser); line, I want to work with the user variable as with normal local state. In this example, I don’t care that local changes with user will not reflect on user at server side – when I’ll be ready for reflecting, I’ll invoke the appropriate mutation.

What will be instead of useMagic and toLocalState?

Share
Improve this question

1 Answer
1

Reset to default


0

It seems like you’re looking for a way to manage the data retrieved from GraphQL using Relay in a more straightforward manner without relying on the structure provided by Relay’s hooks. You want to convert the data to a more traditional React state pattern. While this approach might not leverage Relay’s optimizations fully, you can achieve what you’re looking for by combining the useLazyLoadQuery hook and local React state.

Here’s how you can achieve that using your example:

import type { AppQueryType } from 'AppQueryType.graphql';
import React, { useState } from 'react';
import { graphql, useLazyLoadQuery } from 'react-relay';

const AppQuery = graphql`
  query AppQuery($id: ID!) {
    user(id: $id) {
      name
    }
  }
`;

function NameLoader() {
  const [userId, setUserId] = useState(null); // User ID state
  const data = useLazyLoadQuery<AppQueryType>(AppQuery, { id: userId });

  return (
    <>
      <Button onClick={() => setUserId('4')} disabled={userId != null}>
        Reveal your name!
      </Button>
      {data.user ? <h1>{data.user.name}</h1> : null}
    </>
  );
}

In this example, I’ve used the useLazyLoadQuery hook to fetch the data when the user ID changes. When the button is clicked, the userId state is updated, causing the query to fetch the user data. The fetched user data is stored in the data variable.

Please note that by using this approach, you’re not taking full advantage of Relay’s optimizations, but it provides a more familiar React state management approach. If you later decide to use Relay’s optimizations more extensively, you might need to refactor your components to adhere to Relay’s conventions more closely.

Share
Improve this answer

3

  • Thank you for the answer. Would you please to tell me how I can change the data correctly? Maybe via const [ dataState, setDate ] = useState(data)? Is it fine during re-rendering?

    – Takeshi Tokugawa YD

    45 mins ago


  • 2

    @TakeshiTokugawaYD Just a heads up, this user is serially relying on ChatGPT to generate and post answers, which is prohibited. It's likely this user doesn't have any real knowledge about GraphQL or RelayJS, and it's not worth interacting with them.

    – Sean

    29 mins ago


  • @Sean Thank you for the alert but… How have you knew it?

    – Takeshi Tokugawa YD

    25 mins ago




Leave a Reply

Your email address will not be published. Required fields are marked *