# Component

A Component is a way to visualize data, handle input, and make your dreams come true. When registering a Component in a plugin's [Package file](https://docs.navigaglobal.com/writer/7.2.0/developer-guide/writer-plugin-building-blocks/package), its possible to couple it with a Node, but it's also completely possible to create a Component independently of a Node. When creating sidebar plugins, it's preferred to have one of these independent Components, and handle any NewsItem manipulation from within your plugin classes.

## The render function

The most important function in a Component is its `render` function. This function should return a `VirtualElement` created by using the helper function `$$`. The `$$` function takes either a tag-name as input, to create a DOM-element, or a Substance Component, which in turn calls that Component's `render` function and returns the result.

Creating a simple HTML element:

```javascript
import {Component} from 'substance'

class MyComponent extends Component {
    render($$) {
        return $$('p').append('Hello World!')
    }
}
```

Creating a rendered Component:

```javascript
import {Component} from 'substance'
import {AnotherComponent} from './AnotherComponent'

class MyComponent extends Component {
    render($$) {
        const message = 'Hello World'
        return $$(AnotherComponent, {
            message
        })
    }
}
```

## The `context` Object

In a class extending `Component`, the property `context` exists which exposes some useful services and functionality. In any method in your component, fetch context by using `this.context`.

| Property                  | Description                                                                                                                                                                                |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `state`                   | Gets the current state of the article, contains an object with boolean properties `changed`, `invalid`, `saving`                                                                           |
| `configurator`            | Gets the current configurator                                                                                                                                                              |
| `appStorage`              | Allows access to the localStorage driven app storage                                                                                                                                       |
| `editorSession`           | Allows access to editorSession instance                                                                                                                                                    |
| `labelProvider`           | Gets the labelprovider registered in the Configurator                                                                                                                                      |
| `api`                     | Gets the Api instance, see [Api documentation](https://github.com/Infomaker/dw-documentation/tree/89ef316ecc2545f627b27987592a99f910ebd089/Api/Api.html)                                   |
| `componentRegistry`       | Gets the componentRegistry registered in the Configurator                                                                                                                                  |
| `services.conceptService` | Gets the instance of conceptService, see [Concept interaction](https://github.com/Infomaker/dw-documentation/tree/89ef316ecc2545f627b27987592a99f910ebd089/writer/conceptinteraction.html) |

## Component State and Props

Some excerpts from Substance source code:

> `props` are provided by a parent component. An initial set of properties is provided via constructor.
>
> `state` is a set of flags and values which are used to control how the component gets rendered given the current props. Using `extendState` the component can change its internal state, which leads to a rerendering if the state changes.

Both `props` and `state` affects the rerendering of a Component. To keep it simple, `props` should only be received, and `state` should only be used internally. There are exceptions to this, but it's easier to manage if used in this way. It's possible for Components to communicate using Events.

### Setting Initial State

When a Component renders for the first time, it might not have its entire state fully loaded, and it's good practice to let the Component know what its state looks like for its first render. This is a simple task, as Substance's Component class contains the function `getInitialState` which can be overridden in your own Components.

Component Initial State Example:

```javascript
import {Component} from 'substance'

class MyComponent extends Component {

    getInitialState() {
        return {
            importantMessage: 'Initial Message'
        }
    }

    render($$) {
        const {importantMessage} = this.state
        return $$('p').append(importantMessage) // importantMessage is ensured to exist on first render
    }
}
```

### Sending Props to a Child Component

In order to structure components, it's possible to render a Component within a different Component, and supply that child Component with props from the parent. This is an easy way to avoid bloated Components.

Child Component Example:

```javascript
// MyParentComponent.js

import {Component} from 'substance'

class MyParentComponent extends Component {

    render($$) {
        const myListOfThings = ['hello', 'world', 'foo', 'bar']

        const renderedListOfThings = myListOfThings.map((thing) => {
            return $$(MyChildComponent, {
                item: thing // This object is assigned to `this.props` in MyChildComponent
            })
        })

        return $$('ul').addClass('my-list').append(
            renderedListOfThings
        )
    }

}

export {MyParentComponent}

// MyChildComponent.js

import {Component} from 'substance'

class MyChildComponent extends Component {

    render($$) {
        const {item} = this.props

        return $$('li').append(
            $$('b').append(item)
        )
    }    

}

export {MyChildComponent}
```

Output HTML:

```markup
<ul class="my-list">
    <li><b>hello</b></li>
    <li><b>world</b></li>
    <li><b>foo</b></li>
    <li><b>bar</b></li>
</ul>
```

## Writing a Content Component with Node connection

A Content Component is a Component which is rendered in the Writer's content area, such as text style, content part, image, etc. These Components are coupled with a Node in order to handle the automatic import/export from, and to, NewsML. When writing a Content Component, it's safe to assume that the Component's `props` contain a property `node`, which references an instance of the Component's coupled Node class.

## Component Lifecycle

A Component class has a number of different lifecycle hooks which can be overridden and used to subscribe/unsubscribe from Events, manipulate props/state before they are set, or handle cleanup before the Component is removed from Writer's content area.

| Function Name              | Trigger                                                                  |
| -------------------------- | ------------------------------------------------------------------------ |
| didMount()                 | Before render                                                            |
| didUpdate()                | After render                                                             |
| dispose()                  | When DOMelement is removed                                               |
| willReceiveProps(newProps) | When props update, useful for also changing state which depends on props |
| willUpdateState(newState)  | Before state updates                                                     |

### Override a Component Lifecycle Hook

```javascript
import {Component} from 'substance'
import {AnotherComponent} from './AnotherComponent'

class MyComponent extends Component {

    didMount() {
        // Setup the Component before its first render
    }

    render($$) {
        const message = 'Hello World'
        return $$(AnotherComponent, {
            message
        })
    }
}

export {MyComponent}
```
