親コンポーネントから子コンポーネントにpropsを伝達できない
- 評価
- クリップ 0
- VIEW 602
React,Redux初心者です。
monaca,React,Redux,OnsenUIを使ってアプリケーションを作成しています。
今回、OnsenUIのNavigatorを使っているのですが、上手くpropsを伝達できません。どこに問題があるのでしょうか。
class AlertMainPage extends React.Component{
componentWillMount(){
const that = this
const AlertDB = ncmb.DataStore("Alert")
AlertDB.fetchAll()
.then(function(results){
that.props.showAlertPage(results.length)
})
.catch(function(err){
console.log(err)
})
}
render(){
const AlertContent = styled.div`
height: 100%;
`
const props = this.props
const alertViewList = []
for(var i=this.props.idLen-1; i>=0; i--){
alertViewList.push(<AlertView {...props} id={i}/>)
}
console.log('-----------------');
console.log(this.props);
console.log(this.props.idLen);
console.log(props.idLen);
return(
<Page
renderToolbar={() =>
<Toolbar modifier="material">
<div className='center'>Alert</div>
</Toolbar>
}>
<AlertContent>
{alertViewList}
</AlertContent>
</Page>
)
}
}
//AlertはContainerConponentです。
class Alert extends React.Component{
renderPage(route,navigator) {
const props = route.props || {};
props.navigator = navigator;
return React.createElement(route.component, props)
}
render() {
const props = this.props
console.log(`Alert ${this.props.idLen}`)
return (
<Navigator
swipeable
initialRoute={{
component: AlertMainPage,
//この辺が全然わからない
props: {...props},
idLen: this.props.idLen,
}}
renderPage={this.renderPage}
/>
);
}
}
【追記】
若干進みました。
質問時は本当にどこに問題があるのかわからない状態でした。
・Reduxの設計に問題がある
・OnsenUIの使い方に問題がある
ですが色々試してみて前者については問題ないことがわかりました。
先程のコードをOnsenUIのNavigatorを使わずに似たような構造にしてみました。
class TestNavi extends React.Component {
render() {
return(
<AlertMainPage {...this.props}/>
)
}
}
class Alert extends React.Component{
render() {
console.log(`Alert ${this.props.idLen}`)
return (
<TestNavi {...this.props}/>
);
}
}
するとconsoleには理想通りの値が出力されました。
ですので、今僕がわからないのは、
「OnsenUIのNavigatorを使う時にどのようにしたら親コンポーネントから子コンポーネントにpropsを伝達できるか。」です。
一般的には親コンポーネントから子コンポーネントにpropsを伝達していくときはバケツリレーを避けるためにSpread Attributesを利用するかと思いますが、なぜか上手く行きません。
class Alert extends React.Component{
renderPage(route,navigator) {
const props = route.props || {};
props.navigator = navigator;
return React.createElement(route.component, props)
}
render() {
console.log(`Alert ${this.props.idLen}`)
return (
<Navigator
{...this.props} //普通はココ?
swipeable
initialRoute={{
component: AlertMainPage,
props: {...this.props}, //今回のみココ?でもうまくいかない..。(「普通はココ?」のときよりは若干マシな結果になる)
}}
renderPage={this.renderPage}
/>
);
}
}
またreact-onsenuiのNavigatorのrender()内を見ても、Spread Attributesを使っているように見えますが、なかなか理想通りに動きません。
render() {
const {...others} = this.props;
Util.convert(others, 'animationOptions', {fun: Util.animationOptionsConverter, newName: 'animation-options'});
const pages = this.routes ? this.routes.map((route) => this.props.renderPage(route, this)) : null;
return (
<ons-navigator {...others} ref='navi'>
{pages}
</ons-navigator>
);
}
}
上のリンクの公式ドキュメントを読んだり、実際にNavigatorコンポーネントの中身を読んだりしてみたのですが、いまいち理解することが出ませんでした。
どなたかわかる方がいらっしゃれば教えていただけませんでしょうか。
よろしくお願いします。
【捕捉】
Action
import * as actionTypes from '../actionTypes'
//Alert
export const loadAlertPageAction = (idLen) => {
return{
type: actionTypes.ALERT_PAGE_LOAD,
idLen,
}
}
Reducer
import * as actionTypes from '../actionTypes'
const initialState = {
idLen: null,
}
//Alert
export const alertReducer = (state = initialState, action) => {
switch(action.type){
case actionTypes.ALERT_PAGE_LOAD:
return Object.assign({}, state, {
idLen: action.idLen,
})
default:
return state
}
}
【追記の追記】
質問時の私の理解不足のせいで、もはや若干違う質問になってしまっているかもしれませんが、まだ解決していないのでここで追記して質問を続けさせていただきます。
class AlertNavi extends React.Component{
//ここから
constructor(props){
super(props)
this.state = {
idLen: this.props.idLen,
};
}
//ここまではあってもなくても何も変わらない。
componentWillMount(){
const that = this
const AlertDB = ncmb.DataStore("Alert")
AlertDB.fetchAll()
.then(function(results){
that.props.showAlertPage(results.length)
})
.catch(function(err){
console.log(err)
})
}
render(){
const AlertContent = styled.div'
height: 100%;
'
console.log("this.props.idLen=" + this.props.idLen);
const alertList = []
let idLen = this.props.idLen
for(var i=idLen-1; i>=0; i--){
alertList.push(<RenderAlert {...this.props} id={i}/>)
}
return(
<Page
renderToolbar={() =>
<Toolbar modifier="material">
<div className='center'>アラート</div>
</Toolbar>
}>
<AlertContent>
{alertList}
</AlertContent>
</Page>
)
}
}
class Alert extends React.Component{
renderPage(route, navigator) {
const props = route.props || {};
props.navigator = navigator;
return React.createElement(route.component, props);
}
render() {
console.log("idLen=" + this.props.idLen);
return (
<Navigator
initialRoute={{
component: AlertNavi,
props:{
idLen: this.props.idLen,
showAlertPage: this.props.showAlertPage,
},
// props:{...this.props},
}}
renderPage={this.renderPage}
/>
);
}
}
1回目(?)にreduxのactionが実行されて(画像1行目、2行目)、idLenの値が変更され、nullから2に変わっています。(親コンポーネントの中では)(画像3行目)
しかし問題なのはその次で、その変更されたidLenが子コンポーネントに伝わっていません(画像4行目)
なのでpropsの伝達はできているのはできていると思うのですが、やはりまだ完璧には上手く行っていません。
これは恐らくはOnsenUIの使い方に問題があるのではなく、Reactの設計(ライフサイクルなど実行のタイミングなど)に問題があるのでしょうか。
しかし、追記でも書いたようにOnsenUIのNavigatorを使わずに同じような流れにしてみると、実際うまく行っているので、やはりこのNavigatorの使い方に問題があるのでしょうか。
微妙な質問を繰り返してしまい申し訳ありません。
良かったら教えて頂けると助かります。
よろしくお願いします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
check解決した方法
0
propsの伝達ができないのはコンポーネントの組み合わせ方に問題がありました。
結論を書くと
main → Tabbar ─→ Navigator → A → B → C
└→ Navigator → A' → B' → C'
という構成です。
AコンポーネントはReduxのProviderなどを使うところ
BはContainerComponent
CはPresentationalConponentです。
TabbarとNavigatorをこの親子関係で組み合わせることで、Reduxも上手く動作するようになりました。
単純にNavigatorを使ってpropsを渡したい場合は
<Navigator
// {...this.props} ここではない!
initialRoute={{
component: PageAlert,
props: {...this.props}, // ここ!
}}
renderPage={this.renderPage}
/>
こんな感じで書くと良さそうです。
また、さらに詳しくまとめましたので良かったら読んでみて下さい
OnsenUI(React)のNavigator,Tabbar+Reduxを使う時の構成の注意点について
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
reducerとactionのコードも記述してもらえますか?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
参考にならないかもしれませんが、
私の場合は、以下のやり方で、コンポーネント間でpropsを伝達しています。
例)コンポーネントA→コンポーネントBへNavigatorでPushPageでの画面遷移した時のpropsの値の引き渡し。
コンポーネントA
this.props.navigator.pushPage({
component: コンポーネントB,
props: {
value: 'hoge',// 設定値
},
});
コンポーネントB
/* コンストラクタ */
constructor(props) {
super(props);// これは必要
this.state = {
data: this.props.value,// コンポーネントAのpropsのvalueを取得
};
受け手側のコンポーネントBのコンストラクタで、super(props);を行った後、
コンポーネントAで設定したpropsのvalueの値を引き渡すことが出来ます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。