機能拡張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
からカスタムイベントが発火される。そのイベントにあるitems
をTeamProductList
とTeamInspireList
に引き渡す。
フラグメント
team-search-box
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
として構築する。
結果
その結果、次のような画面が表示される。