# Component Structure

#### Overview

* [**General**](#general-setup) ([Template](#template), [Example](#example))
* [**MUI Styled Components**](#mui-styled-components-1) ([Template](#template-1), [Example](#example))

***

## General

{% hint style="info" %}
Location of **layout** and **utility/reusable** components: `/src/components/`\
Location of **page-related** components: `/src/pages/[page]/_components/`
{% endhint %}

**Notes:**

* Only **1 exported function** per component file (the main/"exported" component)
  * If needing to reuse a local component/function/variable/type in another file, it should then be be moved to their own file at that time (and moved to their [proper location](https://aaron-mota.gitbook.io/aarons-style-guide/frontend/todo/broken-reference))
* Use **named export** (vs default export) [\[1\]](https://stackoverflow.com/questions/46913851/why-and-when-to-use-default-export-over-named-exports-in-es6-modules)[\[2\]](https://medium.com/@timoxley/named-exports-as-the-default-export-api-670b1b554f65)[\[3\]](https://medium.com/@rauschma/note-that-default-exporting-objects-is-usually-an-anti-pattern-if-you-want-to-export-the-cf674423ac38#.nibatprx3)
* Use `Props` as the name for exported component's interface/type
  * For additional local components, append "Props" to the local component name `LocalComponentNameProps`
* Destructure top-level props within signature (vs first line destructuring)
  * Then, use first-line destructuring for destructuring individual top-level props when needed

```
// ...
// ...
// ...
```

### Template

```tsx
// Imports

// Constants (Preference 1)

interface Props {}

export function ComponentName({}: Props) {
  // Constants (Preference 2)
  // Hooks
  // State
  // Effects
  // Functions (Preference 2)
  // Constants (Preference 3) (e.g. variables that depend on local state/effects)
  // Render Logic (e.g. isLoading, isError, isDisabled, etc.)
  return (
    <>
      {/* Render */}
    </>
  );
}

// Functions (Preference 1)
// - Components (first)
// - Functions (second)
```

### Example

[*See MUI Styled Components example*](#example-1)

***

## MUI styled components

When creating a utility/reusable component with an MUI component as the "base" component:

* .`Props` interface should extend the MUI component's native props

```tsx
import { Button, type ButtonProps } from '@mui/material'
interface Props extends ButtonProps {...}
```

* Destructure the `sx` prop from `...props` (within the component signature/declaration)

```
export function MuiComponentAdjective({ sx, ...props }: Props) {
    ...
}
```

* Pass in the destructured `sx` prop into the MuiComponent's sx prop after any "default" sx styling
  * Otherwise, passing the `sx` prop to an instance of the MuiComponent will override any "default" `sx` prop styling that exists

```tsx
export function MuiComponentAdjective({ sx, ...props }: Props) {
    <MuiComponent
        sx={{
          // any "default" sx styling for styled MUI component
          ...sx
        }}
        {...props} 
    >
}
```

### Template

<pre class="language-tsx"><code class="lang-tsx">import { MuiComponent, type MuiComponentProps } from '@mui/material';

interface Props extends MuiComponentProps {
  // any unique fields that are not included within MuiComponentProps (aka not a native prop to the MuiComponent)
}

<strong>export function MuiComponentAdjective({ uniqueField, sx, ...props }: Props) {
</strong>  return (
    &#x3C;>
      &#x3C;MuiComponent
        // data-testid="muicomponent-adjective" (when needed for testing)
        // any "default" props for styled MUI component
        sx={{
          // any "default" sx styling for styled MUI component
          ...sx, // allows overriding of "default" sx styling (e.g. scenario where changing the margin would result in better aesthetics on a specific instance of MuiComponentAdjective
        }}
        {...props} // allows overriding of "default" props
      >
        {...}
      &#x3C;/MuiComponent>
    &#x3C;/>
  );
}
</code></pre>

### Example

```tsx
import { IconButton, type IconButtonProps } from '@mui/material';
import { Icon } from './Icon';

interface Props extends IconButtonProps {
  handleClose: () => void;
}

export function IconButtonClose({ handleClose, sx, props }: Props) {
  return (
    <>
      <IconButton
        data-testid="button-close"
        color="inherit"
        size="small"
        onClick={() => handleClose()}
        edge="end"
        sx={{
          opacity: 0.6,
          ...sx,
        }}
        {...props}
      >
        <Icon icon="close" />
      </IconButton>
    </>
  );
}
```
