react-onsenui の Tabbar で子コンポーネントへ props が渡せません
- 評価
- クリップ 0
- VIEW 982
前提・実現したいこと
構成
親コンポーネント(タブバー描画)
|-- HomePage タプ
`-- SettingsPage タブ
HomePageコンポーネントでのイベント発火で親コンポーネントの state を更新し、それをもう一つの SettingsPageコンポーネントへ props として渡したいのですが渡せません。
発生している問題・エラーメッセージ
該当のソースコード
// App.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Page, Tab, Tabbar, Button} from 'react-onsenui';
import 'onsenui/css/onsenui.css';
import 'onsenui/css/onsen-css-components.css';
import './App.css';
// HomePage タブ
const HomePage = (props) => (
<Page>
<Button onClick={props.omikuji}>Click !</Button>
</Page>
);
HomePage.propTypes = {
omikuji: PropTypes.func,
};
// SettingsPage タブ
const SettingsPage = (props) => (
<Page>
{props.scores.map((score) => (
<div key={score.created_at}>{score.fortune}</div>
))}
</Page>
);
SettingsPage.propTypes = {
scores: PropTypes.arrayOf(
PropTypes.shape({
created_at: PropTypes.instanceOf(Date),
fortune: PropTypes.string,
})
),
};
// 親コンポーネント
class App extends Component {
state = {scores: []};
scoreItems = [];
// タブの描画
renderTabs = () => {
return [
{
content: <HomePage key="Home" omikuji={this.handleOnClick} />,
tab: <Tab key="Home" label="Home" icon="md-home" />,
},
{
content: <SettingsPage key="settings" scores={this.state.scores} />,
tab: <Tab key="settings" label="Settings" icon="md-settings" />,
},
];
};
// HomePage タブのボタンクリックでイベント発火
handleOnClick = () => {
const fortunes = ['大吉', '吉', '中吉', '小吉', '末吉', '凶', '大凶'];
let num = Math.floor(Math.random() * fortunes.length);
this.scoreItems.unshift({
fortune: fortunes[num],
created_at: new Date(),
});
this.setState({scores: this.scoreItems.slice()});
};
render() {
return <Tabbar renderTabs={this.renderTabs} />;
}
}
export default App;
試したこと
・コンストラクタ内の scoreItems 変数を props にすると SettingsPage には渡ります
・しかしそれでも SettingsPage 内の <Page /> では "children: Array[0]" となってしまいます
補足情報(FW/ツールのバージョンなど)
$ node -v
v10.14.2
$ npm -v
6.5.0
create-react-app@2.1.2
react(-dom)@16.7.0
onsenui@2.10.6
react-onsenui@1.11.2
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
こんにちは。
ドキュメント で <Tabbar />
の使い方を調べてみると、ご質問に挙げられているコードですと、<Tabbar />
に与える props が足りないのでは?と思いました。
不足と思われたpropsは、以下2点
- onPreChange
- index
です。これらを追加し、また若干修正を入れた App.js
が以下です。
// App.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Page, Tab, Tabbar, Button} from 'react-onsenui';
import 'onsenui/css/onsenui.css';
import 'onsenui/css/onsen-css-components.css';
import './App.css';
// HomePage タブ
const HomePage = (props) => (
<Page>
<Button onClick={props.omikuji}>Click !</Button>
</Page>
);
HomePage.propTypes = {
omikuji: PropTypes.func,
};
// SettingsPage タブ
const SettingsPage = (props) => (
<Page>
{props.scores.map((score) => (
<div key={score.created_at}>{score.fortune}</div>
))}
</Page>
);
SettingsPage.propTypes = {
scores: PropTypes.arrayOf(
PropTypes.shape({
created_at: PropTypes.instanceOf(Date),
fortune: PropTypes.string,
})
),
};
const FORTUNES = ['大吉', '吉', '中吉', '小吉', '末吉', '凶', '大凶'];
// 親コンポーネント
class App extends Component {
state = { scores: [], index: 0 };
// タブの描画
renderTabs = () => {
return [
{
content: <HomePage key="Home" omikuji={this.handleOnClick} />,
tab: <Tab key="Home" label="Home" icon="md-home" />,
},
{
content: <SettingsPage key="settings" scores={this.state.scores} />,
tab: <Tab key="settings" label="Settings" icon="md-settings" />,
},
];
};
// HomePage タブのボタンクリックでイベント発火
handleOnClick = () => {
const num = Math.floor(Math.random() * FORTUNES.length);
const newItem = {
fortune: FORTUNES[num],
created_at: new Date(),
};
this.setState({ scores: [ newItem, ...this.state.scores ] });
};
render() {
return (
<Tabbar
renderTabs={this.renderTabs}
onPreChange={({ index }) => this.setState({ index })}
index={this.state.index}
/>);
}
}
export default App;
参考までに、上記と同じ App.js
を含む Reactアプリを、以下の GitHubレポジトリに上げました。
上記のレポジトリは、古い順に以下の4つのコミットを含みます。
(1) initial commit
(2) Tabberのprops追加、Appのstateにindex追加
(3) fortunesをクリックされる度に作らないようAppの外に移動
上記コミットで、(1) はご質問に挙げられている App.js
をそのままコピペしたもので、次の(2) で、 <Tabbar />に不足と思われたpropsを2点追加しました。これでとりあえず意図通りに動くと思います。(3), (4) は、蛇足ながら、ちょっとしたリファクタ案ですので、採用するかどうかは質問者様にお任せします。
以下の画面キャプチャは、上記のReactアプリを yarn start して、「Click!」 を3回クリックしてから、Settings ページを表示させたところです。
以上参考になれば幸いです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.10%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/12/31 05:29
期待通りに動作するようになりました。
またリファクタ案についても大変勉強になりました。
とくに (4) では、いったん配列に格納した上で Array.slice() するのではなく、スプレッド演算子を用いてよりスマートに処理できることを教えていただきました。
重ねてありがとうございました。
良いお年をお迎えください。
2018/12/31 06:08