# Mosaic + React

## Before we start

This tutorial will guide you through the first steps of using Mosaic in conjunction with React.

If something goes wrong and you are blocked somewhere - feel welcome to check out [the result](https://github.com/tilework/mosaic-tutorials/tree/master/mosaic-react) of this tutorial, we uploaded it to GitHub for you 👍🏻

## Create a project

First of all, let's create a simple React project. We are going to use the most common way to do that. See the command below!

```
npx create-react-app mosaic-101
```

Now let's run the project to make sure we see the same thing.

<div align="center"><img src="https://1841818881-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXlAVa3s6bRxyH4uXz_%2F-MZlXCpnYGcTNpLZ61oU%2F-MZlmNpDxBZhy-tqiOLz%2Fimage.png?alt=media&#x26;token=db6abfa4-4c17-4adc-8c14-747b5b175ec8" alt="Result of running the project"></div>

## Install Mosaic

First of all, we are going to install the `scripts` package and the `mosaic` itself.

{% tabs %}
{% tab title="yarn" %}

```javascript
yarn add @tilework/mosaic-cra-scripts @tilework/mosaic
```

{% endtab %}

{% tab title="npm" %}

```
npm i @tilework/mosaic-cra-scripts @tilework/mosaic
```

{% endtab %}
{% endtabs %}

Then, we replace the `react-scripts` with the `cra-scripts`, which come from the `@tilework/mosaic-cra-scripts` package.

{% code title="package.json" %}

```javascript
{
    "scripts": {
        "start": "cra-scripts start",
        "build": "cra-scripts build",
        "link": "cra-scripts link",
        "test": "cra-scripts test"
    }
}
```

{% endcode %}

## Launch the project

When you launch the project after the modifications above, you should receive the same result as in the first launch - unchanged.

## Prepare source code

In order to use the plugin system and create some plugins for the existing logic, we should put some namespaces into the source code. Let's start with modifying the `App` component and putting a namespace on that!

{% code title="src/App.js" %}

```javascript
/** @namespace App/App */
function App() {
    ...
```

{% endcode %}

## Create an extension

Local extensions, conventionally, are stored in a `packages` directory in the project root. So let's create this directory and initialize an npm module within it!

```bash
.
├── 📁 packages/
│   └── 📁 sample-extension/
│       └── 📄 package.json
├── 📁 src/
│   ├── ...
│   └── 📄 App.js
└── 📄 package.json
```

## Install and enable the extension

First, we need to install the extension. For the local extensions, we need to add it to the dependencies block manually, as follows. Also, we add the `postinstall` and `postupdate` scripts in order for the local package to be symlinked into `node_modules` directory on any interactions with the dependencies.&#x20;

{% code title="package.json" %}

```javascript
{
    "dependencies": {
        "sample-extension": "file:./packages/sample-extension"
    },
    "scripts": {
        "postinstall": "cra-scripts link",
        "postupdate": "cra-scripts link"
    }
}
```

{% endcode %}

In order to enable the extension, we should declare this in the package.json file of one of the enabled extensions or themes. For now, the only enabled Mosaic module in the application is our application, hence we are going to declare this in our main `package.json` file.

{% code title="package.json" %}

```javascript
{
    "mosaic": {
        "extensions": {
            "sample-extension": true
        }
    }
}
```

{% endcode %}

Afterwards, run the dependency installation in your main package in order to trigger the `postinstall` script and link the extension.

{% tabs %}
{% tab title="yarn" %}

```javascript
yarn
```

{% endtab %}

{% tab title="npm" %}

```javascript
npm i
```

{% endtab %}
{% endtabs %}

## Declare a plugin

Inside of the extension we created, let's declare a plugin to modify the App component. The name file which the plugin is located in should end with `.plugin.js` and the file itself should export a configuration object.

For now, let's keep the logic intact, but log a message about the plugin being functional.

{% code title="packages/sample-extension/src/plugin/App.plugin.js" %}

```javascript
const plugin = (args, callback) => {
    console.log('The plugin works!');
    
    return callback(...args);
};

export default {
    'App/App': {
        function: plugin
    }
};
```

{% endcode %}

In order for the application to get the new plugin file, restart the application. It is very important! Then, you will see our message in the console on the main page!

![](https://1841818881-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXlAVa3s6bRxyH4uXz_%2F-MZm1s3TaVYA_osRprVy%2F-MZm2XAZmTRVT5S56Nwi%2Fimage.png?alt=media\&token=c21c6eea-2454-4f5b-ace9-3bd351a7558c)

## Add an element to the page

Let's modify the previously created plugin declaration file in order to append an element to the page. And, let's remove the `console.log`, we don't need it anymore.

```jsx
const plugin = (args, callback) => {
    return (
        <>
            {callback(...args)}
            <p>I bring the message from the plugin!</p>
        </>
    );
};
```

After declaring this, we are going to see our additional paragraph rendered on the page.

![](https://1841818881-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXlAVa3s6bRxyH4uXz_%2F-MZm1s3TaVYA_osRprVy%2F-MZm3vESN1EG688qv9Fu%2Fimage.png?alt=media\&token=e6cabe24-0661-4faa-823e-b2b778db14db)

## Refactor thinking about SRP

In order for the application to be properly extensible, the logic within it should be granular. Modifying React trees after creation is considered a bad practice, we are going to use a different approach.

We are going to refactor the App component, in order for some additional contents to be able to be added to it without any additional effort. To do that, we'll separate the part which renders header's items from the other logic, so that we can append items there, instead of appending items to the app component itself!

```jsx
/** @namespace App/renderHeaderContents */
function renderHeaderContents() {
  return (
    <>
      <img src={logo} className="App-logo" alt="logo" />
      <p>
        Edit <code>src/App.js</code> and save to reload.
      </p>
      <a
        className="App-link"
        href="https://reactjs.org"
        target="_blank"
        rel="noopener noreferrer"
      >
        Learn React
      </a>
    </>
  )
}

/** @namespace App/App */
function App() {
  return (
    <div className="App">
      <header className="App-header">
        {renderHeaderContents()}
      </header>
    </div>
  );
}
```

&#x20;After this, let's change the previously created plugin declaration file to add an item to the `header`, not below the `App` component.&#x20;

```jsx
export default {
    'App/renderHeaderContents': {
        function: plugin
    }
};
```

## Enjoy the results

After all of the actions above are complete, you are going to see this result. The additional element will be appended right to the middle of the page!

![Properly functioning plugin](https://1841818881-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXlAVa3s6bRxyH4uXz_%2F-MZm74FyDNXQrTGHnZt2%2F-MZm7GMX3l_QVyntUrHe%2Fimage.png?alt=media\&token=be70b9ac-8914-44c9-a03c-33b20f1766b3)
