ヒント
このレッスンは、New Relic アプリケーションをゼロから構築する方法を学習するコースの一部です。 まだご覧になっていない方は、概要をご覧ください。
コースの各レッスンは前回のレッスンに基づいて構築されるため、このレッスンを開始する前に、前回のレッスン「選択したバージョンを保持する」を完了していることを確認してください。
このチュートリアルでは、A/B テスト アプリケーションを構築します。 このアプリケーションは、Web サイトで進行中の A/B テストに関するデータを表示し、それを使用して、どのページ デザイン バージョンがユーザーを引き付けるのに最も効果的かを決定します。 その包括的な目標の一部として、実験の勝者を決定してテストを終了できるセクションを構築します。
残念ながら、このセクションのコードとデザインにはいくつか問題があります。 このコースの最後に、 End test [テストの終了]を押すと、ウェブサイトのバックエンド サーバーに、すべての顧客にここで選択したバージョンが表示されるように指示されます。 これは、Web サイトに不可逆な変更を加える破壊的な動作です。 End test [テスト終了]を押すことによる破壊性を考慮するには、アプリケーションのいくつかの機能を変更する必要があります。
- 注目を集めるためにボタンを重要に見せましょう
- テストを途中で終了しないように、終了する前に確認メッセージで自分自身に警告します。
確認モーダルを表示または非表示にする
コースワークリポジトリのpresent-confirmation-modal/ab-test
ディレクトリに変更します:
$cd nru-programmability-course/present-confirmation-modal/ab-test
このディレクトリには、コースのこの時点でアプリケーションに必要なコードが含まれています。 各レッスンの開始時に正しいディレクトリに移動することで、カスタム コードが残され、間違ったコードがレッスン間で持ち越されることがなくなります。
nerdlets/ab-test-nerdlet/end-test.js
で、 DESTRUCTIVE
スタイルを使用するようにButton
を更新します。
import React from 'react';import { Button, Grid, GridItem, HeadingText, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE}>End test</Button> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
nru-programmability-course/present-confirmation-modal/ab-test
にある Nerdpack のルートに移動します。
Nerdpack の新しい UUID を生成します。
$nr1 nerdpack:uuid -gf
既存の Nerdpack を含むコースワーク リポジトリを複製したため、独自の一意の識別子を生成する必要があります。 この UUID は Nerdpack を New Relic アカウントにマッピングします。
アプリケーションをローカルで提供します。
$nr1 nerdpack:serve
https://one.newrelic.com?nerdpacks=localにアクセスし、 Apps [アプリ] > Your apps [あなたのアプリ]でアプリケーションを表示します。
これで、ボタンの破壊的な結果を伝えるようにボタンのスタイルを設定しましたが、誤ってクリックするのを防ぐには十分ではありません。 次に、Web サイトのバックエンド用のシールドを作成します。 この追加の保護層では、実際にテストを終了する前に、テストを終了する意図があることを確認する必要があります。
EndTestButton
にModal
を追加します:
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
新しいモーダルには、見出し、確認メッセージ、優勝したデザインバージョン、および 2 つのボタンが含まれます。 これらのコンポーネントのいくつかについては、このコースの後半で詳しく説明します。
Nerdpack がローカルで提供されている状態で、アプリケーションを表示して新しいModal
を確認します。
ヒント
サーバーの実行中は、コードを保存すると自動的に更新されることに注意してください。
モーダルは見た目は素晴らしいですが、3 つの問題があります。
- End test [テスト終了を]クリックする前に存在していた
- 無視することはできない
- 実際には選択していないのに、常に「バージョンA」を選択したと表示されます。
次の手順では、これら 3 つの問題をすべて修正します。
EndTestButton
で、 state
をmodalHidden
の値で初期化します。
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor(props) { super(props);
this.state = { modalHidden: true, } }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
modalHidden
モーダルを非表示にするかどうかを決定します。 End test [テストの終了を]選択した場合にのみモーダルを表示するため、 modalHidden
のデフォルト値はtrue
です。
Modal
にmodalHidden
を供給します:
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, } }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal hidden={this.state.modalHidden}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
まず、コンポーネントのプロパティを受け入れるコンストラクターを作成しました。 これにより、コンポーネントはEndTestSection
で渡したmodalHidden
プロパティにアクセスできるようになります。 次に、 Modal
コンポーネントのhidden
プロパティにmodalHidden
の値を指定します。
2 つの新しいメソッドをEndTestSection
に追加してバインドします。
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal hidden={this.state.modalHidden}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
ユーザーがモーダルとどのように対話するかに応じて、それぞれcloseModal
とshowModal
を使用してモーダルを閉じたり表示したりします。
End test [テスト終了を]クリックしたときにモーダルを表示します:
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
ここでは、 Button
コンポーネントのonClick
イベントのコールバックとしてshowModal()
を指定しました。
https://one.newrelic.com?nerdpacks=localに戻り、変更内容を確認します。
モーダルはデフォルトで非表示になっています。 モーダルを表示するには、 End test [テスト終了を]をクリックします。
Modal
コンポーネントのonClose
コールバックと、 Yes, end test [はい、テストを終了]ボタンおよびNo, continue test [いいえ、テストを続行]ボタンからモーダルを閉じます。
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton>End test</EndTestButton> </GridItem> </Grid> }}
https://one.newrelic.com?nerdpacks=localに戻り、変更内容を確認します。
End test [テスト終了]をクリックします。 モーダルが開き、確認メッセージが表示されます。 モーダルを閉じるには、右上のX 、いずれかのボタン、または左側の暗いスペースをクリックします。
「バージョン B」を選択した場合でも、モーダルには「バージョン A」を選択したと表示されることに注意してください。 これは、「バージョン A」がModal
テキストにハードコードされているためです。 次に、それを動的にします。
モーダルで選択したバージョンを使用する
EndTestSection
で、 selectedVersion
をEndTestButton
に渡します。
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version A</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton> </GridItem> </Grid> }}
これで、 EndTestButton
コンポーネントのプロパティから選択したバージョンにアクセスできるようになりました。
確認メッセージにselectedVersion
使用します:
import React from 'react';import { BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton> </GridItem> </Grid> }}
https://one.newrelic.com?nerdpacks=localに戻り、変更内容を確認します。
メニューから「バージョン B」を選択します。 End test[テスト終了]をクリックすると、確認モーダルに「バージョン B」が表示されます。
完了したら、ローカル サーバーのターミナル ウィンドウでCTRL+C
を押して、New Relic アプリケーションの提供を停止します。
おめでとうございます。多くの作業が行われました。その成果はアプリケーションの有用性に表れています。 モックデータを表示するグラフを作成しました。 チャートを読みやすい構造に整理しました。 ユーザーがテストと対話するためのインターフェースを追加しました。 ここで、実際のデータが必要になります。 次のレッスンでは、グラフ内の模擬データをバックエンド サービスの実際のデータに置き換えます。
ヒント
このレッスンは、New Relic アプリケーションをゼロから構築する方法を学習するコースの一部です。 次のレッスンに進みましょう: NrqlQuery コンポーネントをナードレットに追加します。