4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

react-blessedを使ってみる

Last updated at Posted at 2018-09-17

概要

react-blessedは、Reactのblessed.js向けのrendererです。

blessed.jsのウィジェットを、Reactのコンポーネントを使用して描画することができます。

ターミナル上で動作するアプリを作成する際に便利そうだったため、使ってみました。

動作環境

  • Ubuntu 18.04
  • Node.js 8.11.4
  • blessed 0.18.1
  • react-blessed 0.3.0
  • Babel 7

インストール

$ yarn add blessed react react-blessed

$ yarn add @babel/cli @babel/core @babel/plugin-transform-react-jsx @babel/plugin-transform-modules-commonjs @babel/plugin-proposal-class-properties --dev

Hello world

ビルド設定

.babelrcに必要な設定を記述します

.babelrc
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx"],
    ["@babel/plugin-transform-modules-commonjs"],
    ["@babel/plugin-proposal-class-properties"]
  ]
}

ソースコード

src/index.js
import React, { Component } from 'react';
import blessed from 'blessed';
import { render } from 'react-blessed';

class App extends Component {
  render() {
    // blessed.jsのBoxを描画する
    return (
      <box
        width='100%'
        height='10%'
        border={{ type: 'line' }}
        style={{ border: { fg: '#888' } }}>
        Hello, world
      </box>
    );
  }
}

const screen = blessed.screen({
  autopadding: true,
  smartCSR: true,
  title: 'Test',
  fullUnicode: true,
});

// Escapeキーで終了
screen.key(['escape'], (ch, key) => {
  process.exit(0);
});

render(<App></App>, screen);

ビルド

ビルドする際は、package.jsonにスクリプトを記述しておくとよいと思います。

ウォッチしたい場合は、--watchをつけます。

package.json
  "scripts": {
    "build": "babel src --out-dir lib"
  }
$ yarn run build

実行

$ node ./lib/index.js

Hello, worldが画面に出力されると思います。

Escapeキーを押すと、終了します。

tags

blessed.jsのタグを利用する際は、要素に対してtags属性を指定します。

その際に、タグを含むテキストを子として指定するのではなく、

content属性に指定する必要があります。

class App extends Component {
  render() {
    // <text tags>{'{green-fg}{bold}Hello, world{/bold}{/green-fg}'</text>
    // ↑だと、タグが解釈されない
    return (
      <text
        tags
        content={'{green-fg}{bold}Hello, world{/bold}{/green-fg}'}>
      </text>
    );
  }
}

refs

react-dom同様、ref属性が使えます。

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      selectedUser: ''
    };
  }

  componentDidMount() {
    // コンポーネントに対する参照
    this.refs.userList.focus();
  }

  onUserSelected(item) {
    this.setState({ selectedUser: item.content }); 
  }

  render() {
    return (
      <box height='40%' border={{ type: 'line' }}>
        <box height='10%'>{'selected: ' + this.state.selectedUser}</box>
        <box top='10%' height='20%'>
          <UserList
            ref='userList'
            onUserSelected={this.onUserSelected.bind(this)}
            users={['hoge', 'fuga', 'piyo']}>
          </UserList>
        </box>
      </box>
    );
  }
}

class UserList extends Component {
  focus() {
    // blessed.jsのNodeに対する参照
    this.refs.list.focus();
  }

  render() {
    const { users, onUserSelected } = this.props;

    return (
      <list
        ref='list'
        onSelect={onUserSelected}
        items={['hoge', 'fuga', 'piyo']}
        style={{
          selected: {
            bg: '#373b41',
            fg: '#c5c8c6'
          }
        }}
        vi
        keys>
      </list>
    );
  }
}

ref属性を指定した要素は、コンポーネントのrefsプロパティから参照することができます。

prop-types

import PropTypes from 'prop-types';

class UserList extends Component {
  static propTypes = {
    users: PropTypes.func.isRequired,
    onUserSelected: PropTypes.func.isRequired
  };

  ...
}

neo-blessed

blessed.js自体は、現在、あまりメンテナンスされていないようです。

そのため、neo-blessedというfork版が存在します。

react-blessedからneo-blessedを利用する際は、以下の設定を記述します。

import blessed from 'neo-blessed';
import {createBlessedRenderer} from 'react-blessed';

const render = createBlessedRenderer(blessed);

...

render(<App></App>, screen);

ユニットテスト

Enzymeやreact-testing-library等のライブラリは、現在のところ対応していません。

react-test-rendererを使うとよいのだろうか?

import test from 'tape';
import ShallowRenderer from 'react-test-renderer/shallow';
import ChatMessage from './ChatMessage';

test('/components/ChatMessage', assert => {
  const renderer = new ShallowRenderer();

  const output = renderer.render(
    <ChatMessage
      top={0}
      height={20}
      width='100%'
      content='{bold}hoge{/bold}'>
    </ChatMessage>
  );

  assert.equal(
    output.props.content,
    '{bold}hoge{/bold}',
    'should have content'
  );
  assert.end();
});

参考

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?