@shopify/reportify-react v5.4.2
Reportify React
@shopify/reportify-react
is a package that helps you fetch and manage data from Reportify in your React applications.
Getting Started
Install the package in your react project to get started:
yarn add @shopify/reportify-react
Bundled with reportify-react
is a helper script called build-consumer
. This allows for easy tophatting within Shopify repositories. Usage looks like:
yarn build-consumer PROJECT_DIRECTORY
Where PROJECT_DIRECTORY
is the project you intend to test with the reportify-react
changes. Because the primary consumer of reportify-react
is web, here is a sample workflow of how to easily test changes in web:
Using dev
(local development)
- Stop the web server.
- Run
yarn run sewing-kit clean --cache
in web to clear out any existing version ofreportify-react
. - Run
yarn build-consumer web
withinreportify-react
. This will build the project and copy the new build to web. - Start the web server
Using Spin
- Run
spin up web
to create a new instance - Open the terminal in your newly created spin instance
- Run
cd ~/src/github.com/Shopify
- Run
git clone https://github.com/Shopify/reportify-react.git
- Run
cd reportify-react
- Run
code .
to open the reportify-react code in another window - Make your changes to the reportify-react code
- Go back to the terminal in your spin instance
- Run
yarn
- Run
yarn build-consumer web
- Run
rm -rf /src/github.com/shopify/web/build/esbuild/client
- Run
restart shopify--web
- Open web and check that your changes were made
Repeat steps 10-13 every time you make a change to reportify-react.
There are 3 important parts of @shopify/reportify-react
that you need to use to fetch data: ReportifyClient
, ReportifyProvider
, and useReportifyQuery
. A quick sample follows this paragraph immediately, with more in-depth information below.
import {ReportifyClient, ReportifyProvider, useReportifyQuery} from '@shopify/reportify-react';
// Create the client
const client = new ReportifyClient({
source: 'my-source',
refetchToken: () => Promise.resolve('my-token'),
});
// Create a component
function TotalSales({start, end}) {
const queryResult = useReportifyQuery(
`SHOW total_sales FROM sales SINCE ${start} UNTIL ${end}`,
{
pollInterval: 5000,
}
);
if (queryResult.isLoading) {
return <p>Loading...</p>;
} else if (queryResult.hasError) {
console.log(queryResult.errorMessage);
return <p style={{color: 'red'}}>There was an error! Check the console</p>;
}
return (
<div>
<p>Your total sales from {start} to {end} were {queryResult.response.result.data[0][0]}</p>
</div>
);
}
// Wrap your application in a ReportifyProvider
export default function App() {
return (
<ReportifyProvider client={client}>
<TotalSales start="2017-01-01" end="today" />
</ReportifyProvider>
);
}
ReportifyClient
The Reportify client is the means by which you authenticate with and make requests to Reportify.
Options
Option | Type | Required? | Description |
---|---|---|---|
source | string | ✅ | The source parameter helps Reportify identify your client. It should describe your application. Ping #analytics-stack on Slack to find out more about the source param. |
refetchToken | (): Promise<string> | ✅ | refetchToken is a required function that tells the client how to fetch an auth token that can be used when querying Reportify. It takes no parameters and should return a Promise which resolves to a string. |
hostName | string | Specify a Reportify endpoint to query. Default is https://analytics.shopify.com | |
token | string | You may provide an initial token to the client so that it does not need to call refetchToken on its first request. | |
maxRetries | number | Specify the maximum number of times the client should retry your query when receiving a failed response. Default is 1. |
In addition to these options, you can call the following methods on the client once it is created:
Name | Arguments | Description |
---|---|---|
subscribeToQueryStatusEvents | {id: string; callback: (QueryStatus) => void} | Sets up a callback function that is called whenever query status events happen. useReportifyQueryStatus sets up this subscription internally, it is recommened you use that function instead of managing your own subscriber |
ReportifyProvider
The Reportify provider gives its children access to the reportify client. In most cases, you will not work directly with the Reportify client – simply put it high in your component tree and pass it an instance of ReportifyClient
.
Options
Option | Type | Required? | Description |
---|---|---|---|
client | ReportifyClient | ✅ | An instance of ReportifyClient that will be used to query Reportify |
isReactNative | boolean | Whether the environment is React Native |
useReportifyQuery
useReportifyQuery
is a hook that helps you fetch data using ShopifyQL queries you provide.
Options
useReportifyQuery
receives a query as the first argument and an options object with the following available properties as its second argument:
Option | Type | Description |
---|---|---|
pollInterval | number or function | The interval at which you would like the hook to poll for new data. If passed a function, the function will receive pollCount (the number of times the component has polled), previousPollInterval (the last poll interval passed or computed), and previousResponses (the last two responses to be returned from Reportify, with most recent first) |
source | string | The source parameter helps Reportify identify your client. This will override the source given to ReportifyClient /ReportifyProvider for just this query. |
dataOnly | boolean | Determines whether the Reportify response should contain metadata or just data. |
skip | boolean | Determines whether to skip the Reportify query. When skip is true, response is set to undefined , and data is set to an empty array. |
ReportifyQueryOptionsProvider
Sometimes, it might be more convenient to share option values between multiple useReportifyQuery
invocations. Passing options into the <ReportifyQueryOptionsProvider>
will set some default values that can still be overridden in individual useReportifyQuery
invocations.
Options
Option | Type | Description |
---|---|---|
source | string | The source parameter helps Reportify identify your client. This will override the source given to ReportifyClient /ReportifyProvider for any queries in this React component tree as long as options.source passed to useReportifyQuery is undefined . |
dataOnly | boolean | Determines whether the Reportify response should contain metadata or just data. This will become the default behavior for any queries in this React component tree as long as options.dataOnly passed to useReportifyQuery is undefined . |
import {ReportifyQueryOptionsProvider, useReportifyQuery} from '@shopify/reportify-react';
function TotalSales({start, end}) {
// will use shared values from context
// {dataOnly:true, source:'shared-source'}
const queryOne = useReportifyQuery(
`SHOW total_sales FROM sales SINCE ${start} UNTIL ${end}`
);
// will override the context values
// {dataOnly:false, source:'a-new-source'}
const queryTwo = useReportifyQuery(
`SHOW total_sales FROM sales SINCE ${start} UNTIL ${end}`,
{
dataOnly: false,
source: 'a-new-source'
}
);
// ...
}
export default function Section() {
return (
<ReportifyQueryOptionsProvider options={{dataOnly: true, source: 'shared-source'}}>
<TotalSales start="2017-01-01" end="today" />
</ReportifyQueryOptionsProvider>
);
}
useReportifyAST
useReportifyAST
is a hook that fetches Reportify data formatted as an abstract syntax tree (AST).
Options
useReportifyAST
receives a ShopifyQL query string as its first argument and an optional second argument in the form of an object with the following properties:
Option | Type | Description |
---|---|---|
source | string | The source parameter helps Reportify identify your client. This will override the source given to ReportifyClient /ReportifyProvider for just this query. |
useReportifyAST
returns an object containing the following parameters:
Option | Type | Description |
---|---|---|
ast | Object | An abstract syntax tree of the query results |
loading | boolean | Represents whether or not the query is still loading |
error | boolean | Represents whether or not the query returns an error |
Example
const {ast, loading, error} = useReportifyAST('SHOW total_sales FROM sales SINCE -1d UNTIL -1d', {source: 'example'});
useReportifyQueryStatus
useReportifyQueryStatus
is a hook provides the status of the queries fired by the client object. It provides a consistent status response for all of the queries that are requested as part of the initial render. This is useful when you have many queries firing at once and need a way to track when they have all resolved.
Return Value
useReportifyQueryStatus
has three possible values:
undefined
: This indicates that no queries have been sent.'pending'
: This indicates that queries have been sent and that the client is awaiting responses from Reportify.'stable'
: This indicates that the queries have resolved and there are no pending queries.'error-auth'
: This indicates that auth errors were returned to the queries, generally indicating an expired Minvera token. This error usually only occurs in development.'error-some'
: This indicates that only some of the queries errored out.'error-all'
: This indicates that all of the queries have errored out.
Caveats
If you are using multiple hooks that each poll, after the first render the status may appear to rapidly switch between pending
and stable
. This is due to the behavior of setTimeout
within the client and the way that the event loop works in the browser. If you intend to use this within an application that polls with multiple hooks on the same page, consider debouncing the return value.
withReportify
withReportify
is a decorator that wraps your components and provides data based on the ShopifyQL queries you provide it.
Options
withReportify
receives a single options parameter with the following properties:
- an optional
source
string that overrides the source options provided in the client. - a
queries
object. The queries object should have the name of the query as the key and an object with the following options as the value:
Option | Type | Required? | Description |
---|---|---|---|
query | string or function | ✅ | The query you want to send to Reportify. query accepts either a string or a function that will recieve the props passed from the parent component; the function should return a valid ShopifyQL string. |
pollInterval | number or function | pollInterval is an optional parameter that defines how often react-reportify will poll for new data for the query being defined. It accepts either a number for a fixed interval or a function that receives the number of times the container has polled which should return a number as well as props passed from the parent component. | |
transform | function | transform is an optional parameter that defines how a ReportifyResponse will be transformed once the response is received. It should return a ReportifyResponse . | |
skip | function | skip is an optional parameter that allows for a query to be skipped. It is a function that receives props passed from the parent component; returning a truthy value will cause the query to be skipped and a falsey value will have normal behavior. Polling is not affected by skipping and timers will restart as soon as a query is determined to be in need of skipping. |
Examples
Here are a few examples of options passed to withReportify
:
Two queries
withReportify({
queries: {
totalSales: {
query: 'SHOW total_sales FROM sales SINCE yesterday UNTIL today',
},
sessions: {
query: 'SHOW total_sessions FROM visits SINCE yesterday UNTIL today',
},
},
});
Dynamic, polling query
withReportify({
queries: {
salesDateRange: {
// `query` receives props passed into the component – in this case,
// that might be something like <MyComponent start="2018-01-01" end="2018-01-31">
query: ({start, end}) => `SHOW total_sales FROM sales SINCE ${start} UNTIL ${end}`,
// Pass a function that slows down polling as time goes on
pollInterval: (pollCount) => pollCount * 5000,
},
},
});
A query with a source
withReportify({
source: 'my-custom-source',
queries: {
totalSales: {
query: 'SHOW total_sales FROM sales SINCE yesterday UNTIL today',
},
},
});
<Query />
<Query />
is an alternative way to fetch data that relies on a render prop instead of wrapping your component.
Props
Prop | Type | Required? | Description |
---|---|---|---|
queries | {[handle: string]: string} | ✅ | The query that will be sent to Reportify. |
source | string | The source parameter helps Reportify identify your client. This will override the source given to ReportifyClient /ReportifyProvider for just this query. | |
children | (queryResults: ResultMap<ResponseShape>): React.ReactNode | A render function that query results are passed to | |
combineUpdates | boolean | Wait for all queries to finish before passing data to children |
withReportifyClient
Sometimes you will need direct access to the methods the client has to help query reportify. When that is the case, you can decorate your component with withReportifyClient
.
withReportifyClient()(MyComponent);
In the example above, MyComponent
will receive a new prop -- reportifyClient
-- with the following methods:
Method | Description |
---|---|
query(shopifyql: string, options?: {endpoint?: string, beta?: boolean, handle?: string, source?: string}): Promise<ReportifyResponse> | Dispatch a reportify query. Calls to query will be batched, just like |
withReportify . | |
exportQueryURL(shopifyql: string, filename: string): Promise<string> | Create a URL that can be used to export a report for the given ShopifyQL query as a CSV. |
fetchCSV(shopifyql: string): Promise<string> | Returns a Blob containing the query result as a CSV |
An example using exportQueryURL
class MyComponent extends React.Component {
render() {
return <button onClick={this.handleClick}>✨</button>;
}
handleClick = async () => {
const {reportifyClient} = this.props; // `reportifyClient` comes from `withReportifyClient` below
const exportUrl = await reportifyClient.exportQueryURL(
'SHOW total_sales FROM sales SINCE -1d UNTIL today',
'my_exported_report',
);
window.location = exportUrl;
}
}
withReportifyClient()(MyComponent);
An example using fetchCSV
class MyComponent extends React.Component {
render() {
return
<>
<button onClick={this.handleClick}>✨</button>
<FileDownloader blob={exportBlob} filename={'test_file'} />
</>
}
handleClick = async () => {
const {reportifyClient} = this.props; // `reportifyClient` comes from `withReportifyClient` below
const csvBlob = await reportifyClient.fetchCSV(
'SHOW total_sales FROM sales SINCE -1d UNTIL today'
);
this.setState({
exportBlob: csvBlob,
});
}
}
withReportifyClient()(MyComponent);
Testing Reportify React
Detail instructions around testing Reportify React can be found in the docs.
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago