機能拡張v.1

前章までは、見た目だけで機能はない。 本章では、簡単な検索機能を実装する。そこから、各フラグメントの連携手段を話す。

サンプルコードは、こちら

組成

team_composite/src/App.js

import TeamSearchBox from '@bit/silver-birder.micro-frontends-sample-collections.team-search-box'
import TeamInspireLabel from '@bit/silver-birder.micro-frontends-sample-collections.team-inspire-label'
import TeamInspireList from '@bit/silver-birder.micro-frontends-sample-collections.team-inspire-list'
import TeamProductList from '@bit/silver-birder.micro-frontends-sample-collections.team-product-list'
import './App.css'
import { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      productItems: ['apple', 'banana', 'grapes', 'mango', 'orange'],
      inspireItems: ['apple', 'banana', 'grapes', 'mango', 'orange']
    }
  }
  componentDidMount() {
    document.querySelector('.team-search-box-button').addEventListener('submit', this.handleSubmit.bind(this))
  }
  handleSubmit(e) {
    this.setState({
      productItems: e.detail.items, 
      inspireItems: e.detail.items,
    });
  }
  render() {
    return (
      <div className="wrapper">
          <div className="team-search-box">
            <TeamSearchBox/>
          </div>
          <div className="team-product-list">
            <TeamProductList items={this.state.productItems}/>
          </div>
          <div className="team-inspire-list">
            <TeamInspireLabel/>
            <TeamInspireList items={this.state.inspireItems}/>
          </div>
      </div>
    );
  }
}

.team-search-box-buttonからカスタムイベントが発火される。そのイベントにあるitemsTeamProductListTeamInspireListに引き渡す。

フラグメント

team_search/src/components/team-search-box/index.js

import React, { Component } from 'react';
import './index.css';

const items = ['apple', 'banana', 'grapes', 'mango', 'orange'];
export default class TeamSearchBox extends Component {
    constructor(props) {
        super(props);
        this.inputValue = '';
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        const filterItems = (arr, query) => {
            return arr.filter(el => el.toLowerCase().indexOf(query.toLowerCase()) !== -1)
        }
        document.querySelector('.team-search-box-button').dispatchEvent(
            new CustomEvent('submit', {
                detail: {
                    items: filterItems(items, this.inputValue) 
                }
            })
        )
    }
    render() {
        return (
            <div>
                <input onChange={(e) => this.inputValue = e.target.value} className="team-search-box-input" placeholder="Please enter keywords ..."></input>
                <button className="team-search-box-button" onClick={this.handleClick}>
                    <span role="img" aria-label="search button">🔍</span>
                </button>
            </div>
        );
    }
}

.team-search-box-buttonを押下された場合、team-search-box-inputのキーワードが含まれているitemsを抽出する。 そのitemsをカスタムイベントとして発火する。

team-product-list

team_product/src/components/team-product-list/index.js

import React, { Component } from 'react';
import TeamProductItem from '../team-product-item/index';

export default class TeamProductList extends Component {
    render() {
        return (
            <div>
                {this.props.items.map((item) => {
                    return <TeamProductItem key={item} name={item} className="item"></TeamProductItem>;
                })}
            </div>
        );
    }
}

ProductList{this.props.items}から構築する。

team-inspire-list

team_inspire/src/components/team-inspire-list/index.js

import React, { Component } from 'react';
import TeamInspireItem from '../team-inspire-item/index';

const recommendItems = {
    apple: ['apple pie'], 
    banana: ['banana juice'], 
    grapes: ['grape mousse'], 
    mango: ['mango ice'], 
    orange: ['orange cake']
}
export default class TeamInspireList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            items: this.props.items.map((item) => recommendItems[item]).flat()
        }
    }
    componentDidUpdate(prevProps) {
        if (this.props.items.join('') === prevProps.items.join('')) {
            return;
        }
        this.setState({
            items: this.props.items.map((item) => recommendItems[item]).flat()
        })
    }
    render() {
        return (
            <div>
            {this.state.items.map((item) => {
                return <TeamInspireItem key={item} name={item} className="item"></TeamInspireItem>;
            })}
        </div>
        );
    }
}

{this.props.items}からrecommendItemsのキーにマッチする値を抽出する。 それをInspireListとして構築する。

結果

その結果、次のような画面が表示される。

04_function_1_client_side_composition_tutorial
Fig. 118 04_function_1_client_side_composition_tutorial

results matching ""

    No results matching ""