> ## Documentation Index
> Fetch the complete documentation index at: https://help.experro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate a component with widget

As you have seen in the ['How to create widget's section's Step: 1'](./create-widget/#step-1), that we have already created a component and make sure to make a neccesary changes in respactive `index.ts` files as well in following **Steps** of it.

In Step 1 of the ['How to create widget's section's Step: 1'](./create-widget/#step-1), section, you've observed that we've created a component and ensured that the necessary changes are made in the respective `index.ts` files as well, as outlined in the subsequent steps.

When you made your Widget, you likely created a folder for the component. In this folder, you have files like a .tsx file which returns JSX, where you define how the component looks and an index.ts file that goes along with it.

```txt theme={null}
src
 └── components
        ├── cms-library
            ├── exp-test-component
                ├── exp-test-component.tsx
                ├── exp-test-component-controller.tsx
                └── index.ts
```

For the component file, which in our scenario is named `exp-test-component.tsx`, it might vary based on your requirements. The file name could also be different depending on the specific component you're creating.

The component file may appear similar to the snippet below:

`exp-test-component.tsx`

```js theme={null}
/**
 * Renders an exp-test-component component.
 * @param props - Components props.
 * @returns
 */
const ExpTestComponent = (props: any) => {
  const { id, component_content } = props;

  return <div>// ...components JSX</div>;
};

export default ExpTestComponent;
```

In the component's props, you'll receive all the traitConfig objects with their internalName keys as props. For instance, if traitConfig includes a trait like this:

```js theme={null}
{
     type: "exp_checkbox",
     displayName: "Show Heading",
     internalName: "showHeadingText",
}
```

Its internalName would be showHeadingText. When you need to access the selected and updated value of this trait, you can directly destructure it from the props, and you'll obtain the value of the trait "Show Heading" in it.

```js theme={null}
const { id, showHeadingText } = props;
```

> #### Default `id` as a prop

<Info>You'll notice that each component receives a default prop named `id`. This prop is automatically provided to each component integrated with the widget. You can directly destructure it from the component's props.</Info>

***

`exp-test-component-controller.tsx`

To implement all the business logic for the component, we'll create a component-controller file, responsible for managing all the business logic. In the context of developing a React component, it's important to centralize all state management, including `useState`, `useEffect`, and other state manipulations, within this file exclusively. The `exp-test-component.tsx` will solely focus on rendering JSX based on the state managed in the controller file.

So, at this point, we'll retrieve the data of the selected **Content Model** record. The selection is made from the pop-up of the trait type **exp\_contentModalPopUp**. This trait returns data in terms of the selected record's `id`, from which we'll fetch the record's data by making an API call in the controller file.

So, basic struture look's like for the each controller file as below snippet.

```js theme={null}
const ExpTestComponentController = (props: any) => {
  const { id, contentModel, modelInternalName } = props;

  /* This key need's to be unique for all the component you create for the Drag-&-Drop.
   * const modelKeyForSSR = "tes-component-ssr";
   */

  /* In this context, a reducer has been implemented to efficiently manage and handle
   *  multiple states simultaneously, thus streamlining the process of state manipulation.
   */
  const {
    componentDataDispatcher,
    setComponentDataDispatcher,
    isComponentLoaded,
  }: any = ExpComponentDataDispatcher({
    id,
    modelInternalName,
    modelKeyForSSR: modelKeyForSSR,
  });

  let parsedContentModel: ContentModelDataInterface | undefined;

  if (contentModel?.trim().length)
    parsedContentModel = JSON.parse(contentModel);

  /* You will find this useEffect which looks same in each component in which is
   * responsible for making an utilizig a common fuinction which gets data data of selected
   * record baised on the "internalName" and the "parsedContentModel".
   */

  useEffect(() => {
    if (isComponentLoaded) {
      setComponentDataDispatcher({
        type: expCommonDispatcherKeys.fetchingData,
      });
      if (contentModel?.trim()?.length) {
        (async () => {
          setComponentDataDispatcher({
            type: expCommonDispatcherKeys.dataFetched,
            data: await (parsedContentModel,
            modelInternalName,
            modelKeyForSSR,
            id),
          });
        })();
      }
    }
  }, [contentModel]);
};

return {
  componentDataDispatcher,
  contentModel,
};

export default ExpTestComponentController;
```

***

#### ExpComponentDataDispatcher

This serves as a standard dispatch method, offering a dispatcher. Within this common utility, we've integrated a '**useReducer**' hook. Primarily, it accepts `id`, `modelInternalName`, and `modelKeyForSSR` as arguments.

As a result, it furnishes three essential components crucial for component implementation: `componentDataDispatcher`, `setComponentDataDispatcher`, and `isComponentLoaded`.

Here's a breakdown of the provided elements:

* `componentDataDispatcher`: This object contains two values: `{isLoading, componentData}`.

  * **isLoading**: This state is a boolean value (`true/false`) indicating whether the component's data is being fetched or not. Different states utilized within the `useEffect` update the value of this state.
  * **componentData**: This state holds the data of the record obtained after making an API call, facilitated by the common method '`getContentLibraryData`'.

* `setComponentDataDispatcher`: This serves as a setter method for the state, similar to when using `useState`. You specify an object containing type and state values, which are then set by the reducer.

* `isComponentLoaded`: This state holds a boolean value (`true/false`), responsible for indicating whether the component's data has already been fetched or not.

***

In conclusion, this controller returns:

```js theme={null}
{
     componentDataDispatcher,
     contentModel,
}
```

So, let's utilize this values in component, after that component should look like,

```js theme={null}
/**
 * Renders an exp-test-component component.
 * @param props - Components props.
 * @returns
 */
const ExpTestComponent = (props: any) => {
  const { componentDataDispatcher, contentModel } =
    ExpTestComponentController(props);

  return <div>// ...components JSX</div>;
};

export default ExpTestComponent;
```

Now, you can utilize the `componentDataDispatcher`, which contains the `isLoading` and `componentData` state values.

You can utilize the `componentDataDispatcher`'s `isLoading`, `componentData`, and `contentModel` to display the loader of the component or a message indicating to "Select a record".

All the data required for the component will reside in the `componentDataDispatcher`'s `componentData` key. You can utilize this data to render the component and return JSX accordingly.

With Experro Storefront, integrating a component with a widget is a breeze, and customizing it to your exact specifications couldn't be simpler.
