Documentation
Feedback
Guides
Learning Center

Learning Center
Learning Center
Connecting _backend_ and _frontend_
View in Portuguese
This content was migrated from the VTEX Learning Center and is no longer being actively maintained. For the most accurate and up-to-date information, please check the official documentation.

Introduction

Now we will learn how to retrieve data from the backend and display it in the interface. VTEX IO uses GraphQL as a language/technology for data transfer, which makes programming our components quite simple. We will modify our Countdown component to search for the targetDate of the releaseDate field of a VTEX product. To perform GraphQL queries in React, the Apollo Client is used, a state management lib that facilitates the integration of a GraphQL API with the front-end application.

The Apollo Client lib offers native integration with React, through hooks. Thus, making a query means using a hook that will not only perform the queries and fetch the data but will also provide caching and updating the UI state. This integration, called react-apollo is already declared in package.json.

Preparation

  • To implement this functionality, add our countdown block on the product page and also do our tests on this page as well. To do this, do the following:
  1. On your cloned theme (store-theme) access the store/blocks/pdp/product.jsonc file and, on the flex-layout.col#right-col block add the countdown block, right before the buy-button:


    _10
    "product-gifts",
    _10
    + "countdown",
    _10
    "flex-layout.row#buy-button",
    _10
    "availability-subscriber",

  2. Now, run vtex link on your theme again (if the process is not already running). It's done! Now our block is on the product page. Access any of these pages and see the rendered Countdown component.

Release Date Query

  1. First, create a folder in your Countdown app, react/queries and add a productReleaseDate.graphql file to it that will contain the query to be made. In particular, this query will receive a term, which will be the product slug to be retrieved at the launch date. It will call the resolver product, already available through thevtex.search-graphql app, and we will retrieve only the field we need.


    _10
    query productReleaseDate($slug: String) {
    _10
    product(slug: $slug) {
    _10
    releaseDate
    _10
    }
    _10
    }

    Note that the query will need the slug of the product we are looking for. To do so, retrieve this information of the VTEX Product context.

  2. To use this query, it is necessary to add the vtex.search-graphql app as a dependency on your app. We will also need to use the useProduct hook, exported by the vtex.product-context the app, to retrieve the product slug that is loaded on the page. To do this, in your app's manifest.json, add in dependencies:


    _10
    "vtex.search-graphql": "0.x",
    _10
    "vtex.product-context": "0.x"

  3. Now, it is necessary to import the useQuery hooks, to make the query that will return the data we described, and useProduct, to give us information about the current product slug. In addition, it is also necessary to import the query defined previously, which is found in the file productReleaseDate.graphql.


    _10
    // react/Countdown.tsx
    _10
    import React from 'react'
    _10
    ...
    _10
    +import { useQuery } from 'react-apollo'
    _10
    _10
    +import useProduct from 'vtex.product-context/useProduct'
    _10
    _10
    +import productReleaseDate from './graphql/productReleaseDate.graphql'

    It is important to higlight that there is the possibility of your IDE showing an error while importing product-context.

    The prop targetDate will no longer be necessary, so you can remove it.

  4. After that, define the query using the productReleaseDate imported and the useQuery hook, you can find the product data in useProduct hook. Since they are hooks, they only work inside react functional components.


    _10
    + const { product } = useProduct()
    _10
    + const { data, loading, error } = useQuery(productReleaseDate, {
    _10
    + variables: {
    _10
    + slug: product?.linkText
    _10
    + },
    _10
    + ssr: false
    _10
    + })

    linkText will be the same as 'red-front-loading-washer', for example, when your component is rendered in this product's page.

  5. Now that we're using our block in pages that have the product context, it's important to test if this context exists. To do that, let's add the following code block:


    _10
    if (!product) {
    _10
    return (
    _10
    <div>
    _10
    <span>There is no product context.</span>
    _10
    </div>
    _10
    )
    _10
    }

  6. Besides, it is important to deal with the cases in which there is no data fetched when using useQuery and before returning the main component: loading and error In those cases, it is possible to return a span in the countdown component, such as the example below:


    _14
    if (loading) {
    _14
    return (
    _14
    <div>
    _14
    <span>Loading...</span>
    _14
    </div>
    _14
    )
    _14
    }
    _14
    if (error) {
    _14
    return (
    _14
    <div>
    _14
    <span>Error!</span>
    _14
    </div>
    _14
    )
    _14
    }

  7. After sending the changes, access a product page and note that the query is working through a console.log({data}) after calling useQuery, which should show something like this:


    _10
    {
    _10
    data: {
    _10
    product: {
    _10
    releaseDate: '2019-01-01T00:00:00"',
    _10
    __typename: "Product"
    _10
    }
    _10
    }
    _10
    }

  8. At last, but not least, to make Countdown set the hours for the product's releaseDate, change the tick function parameter. You can also remove the props received in the component, as they will no longer be used.


    _10
    -tick(targetDate, setTime)
    _10
    +tick(data?.product?.releaseDate, setTime)

Result using the Red Front-Loading Washer product:

In case of having cases that the countdown is going up or with negative values, don't worry! It's related to the fact that some releaseDate can be in the past.

{"base64":"  ","img":{"width":1663,"height":790,"type":"png","mime":"image/png","wUnits":"px","hUnits":"px","length":394864,"url":"https://user-images.githubusercontent.com/18706156/79596495-0fc28c00-80b7-11ea-8361-35075dba3bd5.png"}}


Well done!

This is the last step of the Store Block course, you did really well and we hope you've learned a lot until this moment. Congratulations!

If you want to continue learning more about how to develop using VTEX IO, we encourage you to start our next course, which focus on teaching how to develop services on top of VTEX IO.

Answer sheet

See answer sheet for Countdown.tsx
Countdown.tsx

_83
// store-block/react/Countdown.tsx
_83
import React, { useState } from 'react'
_83
import { useQuery } from 'react-apollo'
_83
import useProduct from 'vtex.product-context/useProduct'
_83
import { useCssHandles } from 'vtex.css-handles'
_83
_83
import { TimeSplit } from './typings/global'
_83
import { tick, getTwoDaysFromNow } from './utils/time'
_83
import productReleaseDate from './queries/productReleaseDate.graphql'
_83
_83
const DEFAULT_TARGET_DATE = getTwoDaysFromNow()
_83
_83
const CSS_HANDLES = ['countdown']
_83
_83
const Countdown: StorefrontFunctionComponent = () => {
_83
const [timeRemaining, setTime] = useState<TimeSplit>({
_83
hours: '00',
_83
minutes: '00',
_83
seconds: '00',
_83
})
_83
_83
const handles = useCssHandles(CSS_HANDLES)
_83
_83
const { product } = useProduct()
_83
const { data, loading, error } = useQuery(productReleaseDate, {
_83
variables: {
_83
slug: product?.linkText,
_83
},
_83
ssr: false,
_83
})
_83
_83
if (!product) {
_83
return (
_83
<div>
_83
<span>There is no product context.</span>
_83
</div>
_83
)
_83
}
_83
_83
if (loading) {
_83
return (
_83
<div>
_83
<span>Loading...</span>
_83
</div>
_83
)
_83
}
_83
if (error) {
_83
return (
_83
<div>
_83
<span>Error!</span>
_83
</div>
_83
)
_83
}
_83
_83
tick(data?.product?.releaseDate || DEFAULT_TARGET_DATE, setTime)
_83
_83
return (
_83
<div className={`${handles.countdown} c-muted-1 db tc`}>
_83
<h1>{`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}</h1>
_83
</div>
_83
)
_83
}
_83
_83
Countdown.schema = {
_83
title: 'editor.countdown.title',
_83
description: 'editor.countdown.description',
_83
type: 'object',
_83
properties: {
_83
title: {
_83
title: 'I am a title',
_83
type: 'string',
_83
default: null,
_83
},
_83
targetDate: {
_83
title: 'Final date',
_83
description: 'Final date used in the countdown',
_83
type: 'string',
_83
default: null,
_83
},
_83
},
_83
}
_83
_83
export default Countdown

See answer sheet for manifest.json
manifest.json

_20
{
_20
"vendor": "vtex",
_20
"name": "countdown",
_20
"version": "0.0.1",
_20
"title": "Countdown",
_20
"description": "Countdown component",
_20
"defaultLocale": "pt-BR",
_20
"builders": {
_20
"messages": "1.x",
_20
"store": "0.x",
_20
"react": "3.x"
_20
},
_20
"dependencies": {
_20
"vtex.styleguide": "9.x",
_20
"vtex.css-handles": "0.x",
_20
"vtex.search-graphql": "0.x",
_20
"vtex.product-context": "0.x"
_20
},
_20
"$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema"
_20
}

See answer sheet for productReleaseData.graphql
productReleaseData.graphql

_10
# store-block/react/graphql/productReleaseData.graphql
_10
query productReleaseDate($slug: String) {
_10
product(slug: $slug) {
_10
releaseDate
_10
}
_10
}

On this page