---
title: "Sync Data"
framework: react
version: "2.1.2"
---

# Sync Data

Synchronous data sources can be used when data has already been loaded in the application.

A synchronous data source represents a single table of data.

#### Synchronous Data Source

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgStudio, AgStudioRef } from "ag-studio-react";
import {
  AgDataEngine,
  AgDataSourcesDefinition,
  AgReportState,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
} from "ag-studio";

const StudioExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const studioStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [data, setData] = useState<AgDataSourcesDefinition | AgDataEngine>();
  const initialState = useMemo<AgReportState>(() => {
    return {
      pages: [
        {
          id: "page1",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                  { id: "medals.total", aggregation: "sum" },
                ],
              },
            },
            "2": {
              type: "column-chart-grouped",
              dataMapping: {
                categoryKey: [{ id: "medals.country" }],
                valueKey: [
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                ],
                tooltipKey: [],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
            "2": {
              xTrack: 0,
              yTrack: 16,
              xSpan: 24,
              ySpan: 16,
            },
          },
        },
      ],
      selectedPageId: "page1",
      panels: {
        filters: {
          collapsed: true,
        },
        edit: {
          collapsed: true,
        },
      },
    };
  }, []);

  const onApiReady = useCallback((params: AgStudioApiReadyEvent) => {
    fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) => setData({ sources: [{ id: "medals", data }] }));
  }, []);

  return (
    <div style={containerStyle}>
      <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
        <AgStudio
          style={studioStyle}
          className="my-studio-container"
          data={data}
          initialState={initialState}
          mode={"edit"}
          onApiReady={onApiReady}
        />
      </div>
    </div>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <StudioExample />
  </StrictMode>,
);
```

[Live example: Synchronous Data Source](https://www.ag-grid.com/studio/examples/sync-data/sync-data-source/reactFunctionalTs/)

```jsx
const data = useMemo(() => { 
	return {
        sources: [{
            id: 'medals',
            data: [
                {
                    year: 2000,
                    sport: 'Swimming',
                    country: 'United States',
                    // ... other fields
                },
                // ... other rows
            ],
        }],
    };
}, []);

<AgStudio data={data} />
```

Synchronous data sources are represented by the `AgSimpleDataSourceDefinition` interface.

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  | Table ID |
| `name` | `string` |  | Table display name. If not provided, a formatted version of `id` will be used. |
| `description` | `string` |  | AI-facing description of this table's contents and purpose. |
| `data` | `TData[]` |  | Row data. |
| `fields` | `AgFieldDefinition<TRegistry, any, AgFormat<TRegistry>, any>[]` |  | Fields in the table. If not provided, will be inferred from the data. |

## Fields

By default, if no fields are provided, they will be inferred from the data.

It is also possible to provide and customise fields as part of the source definition.

#### Customising Fields

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgStudio, AgStudioRef } from "ag-studio-react";
import {
  AgDataEngine,
  AgDataSourcesDefinition,
  AgFieldDefinition,
  AgReportState,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
} from "ag-studio";

const fields: AgFieldDefinition[] = [
  {
    id: "athlete",
    format: "textFormat",
  },
  {
    id: "age",
    hide: true,
    format: "integerFormat",
  },
  {
    id: "country",
    name: "Location",
    format: "textFormat",
  },
  {
    id: "year",
    format: "integerFormat",
    formatOptions: { format: "0" },
  },
  {
    id: "date",
    format: "dateFormat",
  },
  {
    id: "sport",
    format: "textFormat",
  },
  {
    id: "gold",
    format: "integerFormat",
  },
  {
    id: "silver",
    format: "integerFormat",
  },
  {
    id: "bronze",
    format: "integerFormat",
  },
  {
    id: "total",
    format: "integerFormat",
  },
];

const StudioExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const studioStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [data, setData] = useState<AgDataSourcesDefinition | AgDataEngine>();
  const initialState = useMemo<AgReportState>(() => {
    return {
      pages: [
        {
          id: "page1",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                  { id: "medals.total", aggregation: "sum" },
                ],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
          },
        },
      ],
      selectedPageId: "page1",
      panels: {
        filters: {
          collapsed: true,
        },
        edit: {
          collapsed: true,
        },
      },
    };
  }, []);

  const onApiReady = useCallback((params: AgStudioApiReadyEvent) => {
    fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) =>
        setData({ sources: [{ id: "medals", data, fields }] }),
      );
  }, []);

  return (
    <div style={containerStyle}>
      <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
        <AgStudio
          style={studioStyle}
          className="my-studio-container"
          data={data}
          initialState={initialState}
          mode={"edit"}
          onApiReady={onApiReady}
        />
      </div>
    </div>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <StudioExample />
  </StrictMode>,
);
```

[Live example: Customising Fields](https://www.ag-grid.com/studio/examples/sync-data/sync-custom-fields/reactFunctionalTs/)

The example above demonstrates customising fields. The country field has been titled `Location`, and the age field has been hidden from the UI.

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  | Field ID. |
| `name` | `string` |  | Display name. |
| `description` | `string` |  | Field description. Displayed in the Field Panel |
| `hide` | `boolean` |  | Set to `true` to hide from being selected in the UI. Field can still be used for joins. |
| `editable` | `boolean \| AgFieldEditableKey[]` |  | Controls whether the field can be edited in the UI. |
| `serializer` | `AgFieldSerializer<InferDataTypeFromFormat<TRegistry, TFormat>>` |  | Optional. How the field values will be serialized into state. Defaults to format serializer. |
| `deserializer` | `AgFieldDeserializer<InferDataTypeFromFormat<TRegistry, TFormat>>` |  | Optional. How the field values will be deserialized from state. Defaults to format deserializer. |
| `createValueFormatter` | `AgFieldValueFormatterFactory<InferDataTypeFromFormat<TRegistry, TFormat>, TFormatOptions, any>` |  | Optional. Build a value formatter bound to the field's format options and the runtime API. Defaults to format factory. |
| `blankValue` | `string` |  | Optional. How blank values will be displayed. Defaults to format blank value. |
| `formatOptions` | `TFormatOptions` |  | Optional. Will be passed to the value formatter. |
| `format` | `TFormat` |  | The format type of the field (provides default formatting, etc.). |
| `accessor` | `AgFieldDataAccessor<TData, InferDataTypeFromFormat<TRegistry, TFormat>>` |  | Optional. How to retrieve the value from the data. Either the property key, or a callback. If undefined, `id` will be used as the property key. |
| `cardinality` | `AgFieldCardinality` |  | Optional. Cardinality of the field data. Improves performance if provided. |
| `notBlank` | `boolean` |  | Optional. Does the field contain blank values. Improves performance if provided. |
| `supportedBuckets` | `string[]` |  | Optional. The buckets that this field supports. If undefined, will default to the `supportedBuckets` on the format. |

## Multiple Tables

When multiple tables are provided, they can be linked by providing [Relationships](https://www.ag-grid.com/studio/react/data#relationships).

## Reloading Data

Synchronous data can be reloaded by passing updated data sources to the `data` property.

Note that only the data will be updated. Data sources cannot be added or removed, and fields cannot be updated.

#### Reloading Data

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgStudio, AgStudioRef } from "ag-studio-react";
import {
  AgDataEngine,
  AgDataSourcesDefinition,
  AgReportState,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
} from "ag-studio";

const generateData: (
  sourceData: Record<string, any>[],
) => Record<string, any>[] = (sourceData: Record<string, any>[]) => {
  return sourceData
    .slice(
      Math.floor(window.agRandom() * 100),
      200 + Math.floor(window.agRandom() * 100),
    )
    .map((row: any) => ({
      ...row,
      gold: Math.floor(window.agRandom() * 3),
      silver: Math.floor(window.agRandom() * 4),
      bronze: Math.floor(window.agRandom() * 4),
    }));
};

const StudioExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const studioStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [data, setData] = useState<AgDataSourcesDefinition | AgDataEngine>();
  const initialState = useMemo<AgReportState>(() => {
    return {
      pages: [
        {
          id: "page1",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                ],
              },
            },
            "2": {
              type: "column-chart-grouped",
              dataMapping: {
                categoryKey: [{ id: "medals.country" }],
                valueKey: [
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                ],
                tooltipKey: [],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
            "2": {
              xTrack: 0,
              yTrack: 16,
              xSpan: 24,
              ySpan: 16,
            },
          },
        },
      ],
      selectedPageId: "page1",
      panels: {
        filters: {
          collapsed: true,
        },
        edit: {
          collapsed: true,
        },
      },
    };
  }, []);

  const onApiReady = useCallback((params: AgStudioApiReadyEvent) => {
    fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) =>
        setData({
          sources: [
            {
              id: "medals",
              data: generateData(data),
            },
          ],
        }),
      );
  }, []);

  const reload = useCallback(() => {
    fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
      .then((response) => response.json())
      .then((data) =>
        setData({
          sources: [
            {
              id: "medals",
              data: generateData(data),
            },
          ],
        }),
      );
  }, []);

  return (
    <div style={containerStyle}>
      <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
        <div className="example-controls">
          <div className="controls-row">
            <button id="reload" onClick={reload}>
              Reload
            </button>
          </div>
        </div>

        <AgStudio
          style={studioStyle}
          className="my-studio-container"
          data={data}
          initialState={initialState}
          mode={"edit"}
          onApiReady={onApiReady}
        />
      </div>
    </div>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <StudioExample />
  </StrictMode>,
);
```

[Live example: Reloading Data](https://www.ag-grid.com/studio/examples/sync-data/sync-data-reload/reactFunctionalTs/)
