Original Usage with React.js

This is a description of the first ("original") API for integrating the TAO with React. For a description of the Current API which provides a more React-like declarative approach, take a look here.

It's assumed you have read and are familiar with the Basics guide. If not, then please go back and read through that before trying to learn how to use tao.js with React.

While tao.js itself is client-agnostic, we provide packages to make it seemlessly work with client UI libraries and frameworks.

To start we only have an implementation for React.js. Upcoming and asking for volunteers to help with packages to integrate:

tao.js works seamlessly well with React given the philosophy of building reactive applications at the heart of building applications with tao.js.

To work with React, we make sure to install the @tao.js/react package:

npm install --save @tao.js/core @tao.js/react

@tao.js/core is listed as a peerDependency for the react package so you must install that as well or the package won't work.

There are 2 items we will import and work with to integrate tao.js within our React UI:

Example

Here's a simple example of using a Adapter and Reactor to control display of Components in the UI. We'll use the same Example Application to illustrate integrating React here.

Example Directory Structure

Part of the Application deals with Spaces so it has the following directory:

src/
+- components/
   +- Space/
      - index.js
      - ErrorMessage.js
      - Form.js
      - List.js
      - View.js
- App.css
- App.js

Defining React Components

The Component definitions for ErrorMessage, Form, List and View define basic React Components (both functional and class) and are not aware of nor dependent upon the @tao.js/react package.

They are making use of the TAO export from @tao.js/core in order to set the Application Context.

src/components/space/List.js

Here is an example of functional Components:

import React from 'react';
import TAO from '@tao.js/core';

const SpaceItems = ({ spaces }) =>
  spaces.map(s => (
    <li key={s.id}>
      <button
        onClick={e =>
          TAO.setCtx({ t: 'Space', a: 'Enter', o: 'Portal' }, { Space: s })
        }
      >
        {s.name}
      </button>
    </li>
  ));

const SpaceList = ({ Space }) => (
  <div>
    <h1>Current list of Spaces</h1>
    <h3>
      <button onClick={e => TAO.setCtx({ t: 'Space', a: 'New', o: 'Portal' })}>
        New
      </button>
    </h3>
    <ul>
      <SpaceItems spaces={Space} />
    </ul>
  </div>
);

export default SpaceList;

src/components/space/Form.js

Here is an example full Component for a simple form used to Edit a Space or Create a new Space.

import React, { Component } from 'react';
import TAO from '@tao.js/core';

class SpaceForm extends Component {
  constructor(props) {
    super(props);
    this.state = Object.assign(
      {
        name: '',
        description: ''
      },
      props.Space
    );
  }

  handleChange = event => {
    const target = event.target;
    const val = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    this.setState({
      [name]: val
    });
  };

  handleSubmit = event => {
    event.preventDefault();
    const { a, Space:origSpace } = this.props;
    const updatedSpace = this.state;
    const isNew = a === 'New';
    const saveAction = isNew ? 'Add' : 'Update';
    // TAO.setCtx will use positional args to set the AppCtx data
    TAO.setCtx({ t: 'Space', a: saveAction, o: 'Portal' }, origSpace, updatedSpace);
  };

  handleCancel = event => {
    event.preventDefault();
    const { Space: { id } = {} } = this.props;
    // if tao.a == 'New' then id == undefined
    TAO.setCtx({ t: 'Space', a: 'Find', o: 'Portal' }, { Find: { id } });
  };

  render() {
    const { a } = this.props;
    const Space = this.state;
    const isNew = a === 'New';
    return (
      <div>
        <h1>
          {a} Space {Space.name ? `- ${Space.name}` : ''}
        </h1>
        <form name={`${a}Space`} onSubmit={this.handleSubmit}>
          {isNew ? null : <input type="hidden" name="id" value={Space.id} />}
          <label htmlFor="name">Name:</label>
          <input
            type="text"
            name="name"
            value={Space.name}
            onChange={this.handleChange}
          />
          <br />
          <label htmlFor="description">Description:</label>
          <textarea
            name="description"
            value={Space.description}
            onChange={this.handleChange}
          />
          <br />
          <input type="submit" value="Save" />&nbsp;<button
            onClick={this.handleCancel}
          >
            Cancel
          </button>
        </form>
      </div>
    );
  }
}

export default SpaceForm;

Wiring up Components as Handlers

We then use a Adapter to wire up the Space Components as Handlers for AppCons generated through the course of interacting with the application, and expose a Reactor that will embed the Components provided by the Adapter into the React UI.

src/components/space/index.js

import React from 'react';
import TAO, { AppCtx } from '@tao.js/core';
import { Adapter, Reactor } from '@tao.js/react';
import List from './List';
import View from './View';
import Form from './Form';
import ErrorMessage from './ErrorMessage';

// chain entering a Space with showing the View
TAO.addInlineHandler(
  { t: 'Space', a: 'Enter', o: 'Portal' },
  (tao, { Space }) => {
    return new AppCtx('Space', 'View', 'Portal', { Space });
  }
);

const spaceAdapter = new Adapter(TAO);
spaceAdapter
  .setDefaultCtx({ term: 'Space', orient: 'Portal' })
  .addComponentHandler({ action: 'List' }, List)
  .addComponentHandler({ action: 'View' }, View)
  .addComponentHandler({ action: ['New', 'Edit'] }, Form);

const messageAdapter = new Adapter(TAO);
messageAdapter.addComponentHandler({ term: 'Space', action: 'Fail' }, ErrorMessage);

const SpaceContainer = () => (
  <div>
    <Reactor key="spaceMessages" adapter={messageAdapter} />
    <Reactor key="spaceComponents" adapter={spaceAdapter} />
  </div>
);

export default SpaceContainer;

Including Space Components in the App

Our main App Component needs to then include the ability to view Spaces so we define it like this:

src/App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// import the SpaceContainer
import SpaceContainer from './components/Space';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <SpaceContainer />
      </div>
    );
  }
}

export default App;

Above you will see that App.js imports the default export of the ./Space directory, which is exporting a Reactor Component that it embeds in the main UI.

The Reactor's Adapter will react to AppCon changes and tell the Reactor which Component to render or none if the AppCon doesn't call for one.

More Details

Now that we have an overall understanding of how to integrate tao.js into our React Apps, we can follow the Adapter and Reactor guides to learn more about them individually.

results matching ""

    No results matching ""