質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.86%

  • React.js

    654questions

    Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

  • Onsen UI

    306questions

    HTML5で記述されたモバイルアプリの高速化、およびネイティブアプリライクなUIが作れるフレームワーク。 様々なJavaScriptフレームワークと併せて使用することができます。スマートフォン向けアプリ、Webサイトに必要なアニメーション、UI/UXを実装することが可能になります。

  • Redux

    89questions

親コンポーネントから子コンポーネントにpropsを伝達できない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 322

cloudspider

score 63

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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

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のコードも記述してもらえますか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/26 14:06

    回答ありがとうございます。
    追記しました。

    キャンセル

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の値を引き渡すことが出来ます。

  

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/29 16:50

    回答ありがとうございます
    もう少し詳しくお聞きしたいのですが、コンポーネントAというのは
    <Navigator />と書いてあるコンポーネントのことでしょうか。
    だとしたら、NavigatorのinitialRouteなどは何と書いてあるのでしょうか。

    キャンセル

  • 2017/09/29 18:17

    すみません、親コンポーネントではなく、子コンポーネントでした。
    子コンポーネント間のpropsの連携でした。
    コンポーネントAは、以下の定義になります。
    export default class コンポーネントA extends React.Component {
     中身は省略
    }

    キャンセル

  • 2017/09/29 18:21

    <Navigator/>と書かれた親コンポーネントから子コンポーネント間の同じやり方で、propsの値は連携できます。

    親コンポーネント
    render() {
    return (
    <Navigator initialRoute={{
    component: 子コンポーネント
    ,props:{
    idLen: 3
    }

    }} renderPage={this.renderPage} />
    );
    }

    子コンポーネント
    export default class 子コンポーネント extends React.Component {
    constructor(props) {
    super(props);
    console.log("this.props.idLen=" + this.props.idLen);//3と出力される。
    }
    }

    キャンセル

  • 2017/10/01 16:41

    ありがとうございます。
    OnsenUIのNavigatorに関してはtoshi_7710さんの意見を参考にするとうまくいきました。ありがとうございます。
    しかし、まだ(恐らくはReact設計に関して)、問題が解決していないので、もしよろしければ追記の追記の部分についてアドバイス頂けるとうれしいです。
    よろしくお願いします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Reactでデータが変更された時にメソッドを呼び出したい

    以下のようなコードで、dataに変更があった場合にaddNodsメソッドを呼び出すような実装を行うにはどのようにすればいいでしょうか。 var data = []; cla

  • 解決済

    react-reduxでのconnectについて

    最近ちょっと使い始めたのですが、react.jsのcomponentとreduxとで連携するためにconnectすると思うのですが、実際に作り始めてみるとほとんどのcomponen

  • 解決済

    React.jsにおけるsetState

    React.jsにおいて、stateを定義するためにsetState関数を使用しますが、this.state.hoge = でも値を代入できます。 これらの本質的違いはなんでしょう

  • 受付中

    JSのundefined対策について

    JavaScriptのundefined対策について、スマートな方法がないか試行錯誤しています。 例えば下記のList.jsの例では、msgList配列をmapでループする場合、m

  • 解決済

    react navigationで画面遷移ができない(react native)

    React Nativeの画面遷移でReact Navigationを導入したいと考えています。 イメージとしては、ホームにいくつかサムネイルが並んでいて、これをクリックすると詳細

  • 解決済

    react 複数のクリックイベント

    もしかするとreact以前の問題かもしれないのですが・・・ class Names extends React.Component{ constructor(props

  • 解決済

    React.js でラジオボタンもどきを実装する方法

     前提・実現したいこと Reactでラジオボタンのようなものを作成したいと考えています。 理想とする挙動はボタンが複数あり、その中の一つをクリックするとボタンの色が変わり(色なりチ

  • 解決済

    React Router v4でpropsの受け渡しができない

    こちらの記事を参考に、ルーティング先の component に Props を渡そうと考えています。 具体的には、<Route />で表示するコンポーネントを指定する際に、“c

同じタグがついた質問を見る

  • React.js

    654questions

    Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

  • Onsen UI

    306questions

    HTML5で記述されたモバイルアプリの高速化、およびネイティブアプリライクなUIが作れるフレームワーク。 様々なJavaScriptフレームワークと併せて使用することができます。スマートフォン向けアプリ、Webサイトに必要なアニメーション、UI/UXを実装することが可能になります。

  • Redux

    89questions