Component
Class defined in ui/Component.js#100

A light-weight component implementation inspired by React and Ember. In contrast to the large frameworks it does much less things automagically in favour of synchronous rendering and a minimalistic life-cycle. It also provides up-tree communication and dependency injection.

### Why synchronous rendering?

Synchronous rendering, while it may seem less performant, is necessary because substance must render the model, after it has changed before the next change is triggered by the user.

Asynchronous rendering as it exists in React means that the UI will eventually catch up to changes in the model. This is not acceptable in substance because substance plays with contenteditable and thus, cursor positions, etc are maintained in the browser's DOM. If we went the async way, the cursor in the DOM would be briefly inconsistent with the cursor in the model. In this brief window, changes triggered by the user would be impossible to apply.

### Concepts:

- `props` are provided by a parent component. An initial set of properties is provided via constructor. After that, the parent component can call `setProps` or `extendProps` to update these properties which triggers rerendering if the properties change.

- `state` is a set of flags and values which are used to control how the component gets rendered given the current props. Using `setState` the component can change its internal state, which leads to a rerendering if the state changes. Prefer using `extendState` rather than `setState`.

  Normally, a component maintains its own state. It isn't recommended that a parent pass in or update state. If you find the need for this, you should be looking at `props`.

  State would be useful in situations where the component itself controls some aspect of rendering. Eg. whether a dropdown is open or not could be a state within the dropdown component itself since no other component needs to know it.

- A child component with a `ref` id will be reused on rerender. All others will be wiped and rerender from scratch. If you want to preserve a grand-child (or lower), then make sure that all anchestors have a ref id. After rendering the child will be accessible via `this.refs[ref]`.

- A component can send actions via `send` which are bubbled up through all parent components until one handles it. A component declares that it can handle an action by calling the `handleActions` method on itself in the constructor or the `didUpdate` lifecycle hook.

### Lifecycle hooks

The RenderingEngine triggers a set of hooks for you to define behavior in various stages of the rendering cycle. The names are pretty self explanatory. If in doubt, please check out the method documentation below.

1. Component#didMount
2. Component#didUpdate
3. Component#dispose
4. Component#willReceiveProps
5. Component#willUpdateState

Example

Define a component:

    class HelloMessage extends Component {
      render() {
        return $$('div').append(
          'Hello ',
          this.props.name
        )
      }
    }

And mount it to a DOM Element:

    HelloMessage.mount({name: 'John'}, document.body)

new Component()
Constructor defined in ui/Component.js#108

Construcutor is only used internally.

this.getChildContext()
Method defined in ui/Component.js#167

Provides the context which is delivered to every child component. Override if you want to provide your own child context. Child context is available to all components rendered from within this component's render method as `this.context`.

Returns

Object | the child context

Example

    class A extends Component {
    ...
      getChildContext() {
        // Optional, but useful to merge super's context
        return Object.assign({}, super.getChildContext(), {foo: 'bar'})
      }

      render($$) {
        return $$(B)
      }
    }

    class B extends Component {
      render($$) {
        // this.context.foo is available here
      }
    }

Component

this.getInitialState()
Method defined in ui/Component.js#179

Override this within your component to provide the initial state for the component. This method is internally called by the RenderingEngine and the state defined here is made available to the Component#render method as this.state.

Returns

Object | the initial state

this.getParent()
Method defined in ui/Component.js#188

Provides the parent of this component.

Returns

Component | the parent component or null if this component does not have a parent.

this.getRoot()
Method defined in ui/Component.js#197

Get the top-most Component. This the component mounted using ui/Component.mount

Returns

Component | The root component

this.getLabel()
Method defined in ui/Component.js#224

Short hand for using labelProvider API

Example

    render($$) {
      let el = $$('div').addClass('sc-my-component')
      el.append(this.getLabel('first-name'))
      return el
    }

this.getComponent(componentName, maybe)
Method defined in ui/Component.js#250

Get a component class for the component name provided. Use this within the render method to render children nodes.

Parameters

componentName | String | The component's registration name
maybe | Boolean | if `true` then does not throw when no Component is found

Returns

Class | The ComponentClass

Example

    render($$) {
      let el = $$('div').addClass('sc-my-component')
      let caption = this.props.node.getCaption() // some method that returns a node
      let CaptionClass = this.getComponent(caption.type)
      el.append($$(CaptionClass, {node: caption}))
      return el
    }

this.render($$)
Method defined in ui/Component.js#275

Render the component.

ATTENTION: this does not create a DOM presentation but a virtual representation which is compiled into a DOM element later.

Every Component should override this method.

Parameters

$$ | Function | method to create components

Returns

VirtualNode | VirtualNode created using {@param $$}

this.mount()
Method defined in ui/Component.js#292

Mount a component to the DOM.

Example

    var app = Texture.mount({
      configurator: configurator,
      documentId: 'elife-15278'
    }, document.body)

this.shouldRerender(newProps)
Method defined in ui/Component.js#319

Determines if Component should be rendered again using ui/Component#rerender after changing props. For comparisons, you can use `this.props` and `newProps`.

The default implementation simply returns true.

Parameters

newProps | Object | The props are being applied to this component.

Returns

| a boolean indicating whether rerender() should be run.

this.rerender()
Method defined in ui/Component.js#328

Rerenders the component.

Call this to manually trigger a rerender.

this.triggerDidMount(isMounted)
Method defined in ui/Component.js#374

Triggers didMount handlers recursively.

Gets called when using `component.mount(el)` on an element being in the DOM already. Typically this is done for a root component.

If this is not possible because you want to do things differently, make sure you call 'component.triggerDidMount()' on root components.

Parameters

isMounted |  | an optional param for optimization, it's used mainly internally

Example

    var frag = document.createDocumentFragment()
    var comp = MyComponent.mount(frag)
    ...
    $('body').append(frag)
    comp.triggerDidMount()

this.didMount()
Method defined in ui/Component.js#421

Called when the element is inserted into the DOM. Typically, you can use this to set up subscriptions to changes in the document or in a node of your interest.

Remember to unsubscribe from all changes in the ui/Component#dispose method otherwise listeners you have attached may be called without a context.

Example

    class Foo extends Component {
      didMount() {
        this.props.node.on('label:changed', this.rerender, this)
      }

      dispose() {
        // unless this is done, rerender could be called for a dead, disposed
        // component instance.
        this.props.node.off(this)
      }
    }

Make sure that you call `component.mount(el)` using an element which is already in the DOM.

    var component = new MyComponent()
    component.mount($('body')[0])

this.didUpdate()
Method defined in ui/Component.js#427

Hook which is called after state or props have been updated and the implied rerender is completed.

this.isMounted()
Method defined in ui/Component.js#432
Returns

boolean | indicating if this component has been mounted

this.triggerDispose()
Method defined in ui/Component.js#441

Triggers dispose handlers recursively.

this.dispose()
Method defined in ui/Component.js#455

A hook which is called when the component is unmounted, i.e. removed from DOM, hence disposed. See ui/Component#didMount for example usage.

Remember to unsubscribe all change listeners here.

this.send(action, ...)
Method defined in ui/Component.js#476

Send an action request to the parent component, bubbling up the component hierarchy until an action handler is found.

Parameters

action |  | the name of the action
... |  | arbitrary number of arguments

Returns

Boolean | true if the action was handled, false otherwise

this.handleActions(actionHandler)
Method defined in ui/Component.js#512

Define action handlers. Call this during construction/initialization of a component.

Parameters

actionHandler | Object | An object where the keys define the handled actions and the values define the handler to be invoked. These handlers are automatically removed once the Component is disposed, so there is no need to unsubscribe these handlers in the {@link ui/Component#dispose} hook.

Example

    class MyComponent extends Component {
      constructor(...args) {
        super(...args)
        this.handleActions({
         'openPrompt': this.openPrompt,
         'closePrompt': this.closePrompt
        })
      }
    }

this.handleAction(action, a)
Method defined in ui/Component.js#525

Define an action handler. Call this during construction/initialization of a component.

Parameters

action | String | name
a | Functon | function of this component.

this.getState()
Method defined in ui/Component.js#538

Get the current component state

Returns

Object | the current state

this.setState(newState)
Method defined in ui/Component.js#556

Sets the state of this component, potentially leading to a rerender. It is better practice to use ui/Component#extendState. That way, the code which updates state only updates part relevant to it.

Eg. If you have a Component that has a dropdown open state flag and another enabled/disabled state flag for a node in the dropdown, you want to isolate the pieces of your code making the two changes. The part of your code opening and closing the dropdown should not also automatically change or remove the enabled flag.

Note: Usually this is used by the component itself.

Parameters

newState | object | an object with a partial update.

this.extendState(newState)
Method defined in ui/Component.js#580

This is similar to `setState()` but extends the existing state instead of replacing it.

Parameters

newState | object | an object with a partial update.

this.willUpdateState()
Method defined in ui/Component.js#588

Called before state is changed.

this.getProps()
Method defined in ui/Component.js#596

Get the current properties

Returns

Object | the current state

this.setProps(an)
Method defined in ui/Component.js#605

Sets the properties of this component, potentially leading to a rerender.

Parameters

an | object | object with properties

this.extendProps(an)
Method defined in ui/Component.js#636

Extends the properties of the component, without necessarily leading to a rerender.

Parameters

an | object | object with properties

this.willReceiveProps(newProps)
Method defined in ui/Component.js#647

Hook which is called before properties are updated. Use this to dispose objects which will be replaced when properties change.

For example you can use this to derive state from props.

Parameters

newProps | object |