2016-08-17 2 views
0

react-router router.listen(...)を使用してルートパラメータを取得しようとすると失敗します。 window.location.pathname.split( 'route /')[1]を使って、パラメータを取得できます。任意のヒント ?react-router:ルータリスンイベントからparamを取得できない

私はこれがなぜ起こるのかを理解しようとしてきました。これまでのところ、私はそれが最初のルート変更(URL変更)に失敗したことに気付きました。私の言いたいことは、私のURL変更が/param/yから/param/xに変更されたことです。パラメータを使用できるのは、再度クリックした場合のみです。私はこれが私の行動や私の構成要素と関連していると思いますか?または、リスナーが反応ライフサイクルのどこに置かれているか?

誤ったライフサイクルメソッドでeventlistenerを宣言しているかどうかわかりません。私が思っていたように、私はストアにルーティングを渡していますが、私は思うこのイベントのためにwithRouter(Component)を使用しています。私は代わりに還元状態からルーティング状態を使用する必要があると思います。

import { FETCH_QUESTIONS, SET_ACTIVE_QUESTION } from '../actions/index'; 
import _ from 'lodash'; 

const INITIAL_STATE = { 
    loading: true, 
    list: [], 
    active: 0 

}; 

export default function(state = INITIAL_STATE, action) { 

    switch (action.type) { 

     case FETCH_QUESTIONS: 

      return Object.assign({}, state, { 
       loading: false, 
       list: action.payload 
      }); 

     break; 

     case SET_ACTIVE_QUESTION: 

      // retrieve the active question by the route param `question id` 
      let question_id = parseInt(action.payload); 
      let question = _.find(state.list, function (question) { 
       return question.id === question_id; 
      }); 

      return Object.assign({}, state, { 
       active: question 
      }); 

     break; 

     default: 
      return state; 

    } 

}; 

アプリのエントリポイントindex.js:

import React from 'react'; 
import ReactDOM from "react-dom"; 
import { Router, browserHistory } from 'react-router'; 
import { syncHistoryWithStore } from 'react-router-redux' 
import { createStore, applyMiddleware } from 'redux'; 
import { Provider } from 'react-redux'; 
import routes from './config/routes'; 
import reducers from './reducers'; 
import promise from 'redux-promise'; 

const createStoreWithMiddleware = applyMiddleware(promise)(createStore); 
const store = createStoreWithMiddleware(reducers); 
const history = syncHistoryWithStore(browserHistory, store); 

ReactDOM.render(
    <Provider store={ store }> 
     <Router history={ history } routes={ routes } /> 
    </Provider>, 
    document.getElementById('app') 
); 

router.jsファイル

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import { withRouter } from 'react-router'; 
import { setActiveQuestion, setQuestionAnswer } from '../actions/index'; 
import { bindActionCreators } from 'redux'; 
import { Link } from 'react-router'; 
import Navbar from '../containers/navbar'; 

class Question extends Component { 
    constructor(props) { 
     super(props); 
     this.getClassName = this.getClassName.bind(this); 
    } 
    componentWillMount() { 
     this.setEventListeners(); 
    } 

    setEventListeners() { 
     this.props.router.listen(() => { 
      // using location pathname instead, since props.params fail 
      //let question_id = this.props.params.question_id; 
      let question_id = window.location.pathname.split('question/')[1] 
      this.props.setActiveQuestion(question_id); 
     }); 
    } 

    setAnswer(answer_id) { 
     let question_id = this.props.question.id; 
     this.props.setQuestionAnswer(question_id, answer_id); 
    } 

    getClassName(answers, item_answer_id) { 

     let classes = []; 

     // find the answer for the active question 
     let answer_index = _.findIndex(answers, (answer) => { 
      return answer.question_id === this.props.question.id; 
     }); 

     // if there's no answer yet, skip class placement 
     if (answer_index === -1) { 
      return; 
     } 

     let answer = answers[answer_index]; 

     // Test cases 
     const isUserCorrect =() => { 
      return answer.answer_id == answer.correct_answer_id && item_answer_id == answer.correct_answer_id 
     } 

     const isUserAnswer =() => { 
      return answer.answer_id === item_answer_id; 
     } 

     const isCorrectAnswer =() => { 
      return item_answer_id == answer.correct_answer_id; 
     } 

     // Test and set the correct case classname for styling 
     if (isUserCorrect()) { 
      classes.push('user_correct_answer'); 
     } 

     if (isUserAnswer()) { 
      classes.push('user_answer'); 
     } 

     if (isCorrectAnswer()) { 
      classes.push('correct_answer'); 
     } 

     return classes.length > 0 ? classes.join(' ') : ''; 

    } 

    answersList() { 
     return this.props.question.answers.map((answer) => { 
      return <li className={ this.getClassName(this.props.answers, answer.id) } key={ answer.id } onClick={() => this.setAnswer(answer.id) }>{ answer.text }</li> 
     }); 
    } 

    render() { 
     return (
      <div> 
       <div className='question-container'> 
        <h2>{ this.props.question && this.props.question.question }</h2> 
        <ul> 
        { 
         this.props.question && 
         this.answersList() 
        } 
        </ul> 
       </div> 
       <Navbar /> 
      </div> 
     ); 
    } 
} 

function mapStateToProps(state, ownProps) { 
    return { 
     question: state.questions.active, 
     answers: state.answers 
    } 
} 

function matchDispatchToProps(dispatch) { 
    return bindActionCreators({ 
     setActiveQuestion: setActiveQuestion, 
     setQuestionAnswer: setQuestionAnswer 
    }, dispatch); 
} 

export default connect(mapStateToProps, matchDispatchToProps)(withRouter(Question)); 

ここで減速だ:私はリスナーがあり

コンポーネントを想定します:

import { combineReducers } from 'redux'; 
import questionsReducer from './reducer_questions'; 
import answerReducer from './reducer_answers'; 
import { routerReducer } from 'react-router-redux' 

const rootReducer = combineReducers({ 
    questions: questionsReducer, 
    answers: answerReducer, 
    routing: routerReducer 
}); 

export default rootReducer; 

答えて

1

、あなたが見てみたいことがあります。このようになります、

function mapStateToProps(state, ownProps) { 
    return { 
     my_parameter_name: ownProps.params.my_parameter_name 
    } 
} 

export default connect(mapStateToProps)(MyComponent); 

元のソースコードを変更:ベターその後、説明するには、次のコードを検討することですwithRotuer

それはあなたがあなたのconnect ...

withRouter(connect(function(state, props) { 
    return { question_id: props.params.question_id }; 
})(MyComponent) 

でのparamsオブジェクトにアクセスできるようになります。そして、あなたがcomponentDidMount/componentWillMountcomponentWillReceiveProps(nextProps

componentWillMount() { 
    this.props.setActiveQuestion(this.props.question_id); 
} 

componentWillReceiveProps(nextProps) { 
    if (this.props.question_id != nextProps.question_id) { 
     this.props.setActiveQuestion(nextProps.question_id); 
    } 
} 

のために聞くことができる今、あなたのコンポーネントが知る必要はありません現在の設定では、問題が発生する可能性のあるルート変更(「router.removeListner」が欠落しているため)を聞くのを止めることはありません。

withRouterを説明する良いビデオはここにありますhttps://egghead.io/lessons/javascript-redux-using-withrouter-to-inject-the-params-into-connected-components?course=building-react-applications-with-idiomatic-redux

1

私は本当に感謝する@TryingToImproveフィードバックに基づいて解決策を見つけました。私はwithRouterを使用してMyComponentをラップしてルータの場所の変更を聞く必要があると想定しましたが、明らかに間違っています。理由は、Reducerからのルーティングパラメータを格納するためです。そのため、mapStateToProps中にいつでも呼び出すことができます。代わりにルータを聴取する

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import { withRouter } from 'react-router'; 
import { setActiveQuestion, setQuestionAnswer } from '../actions/index'; 
import { bindActionCreators } from 'redux'; 
import { Link } from 'react-router'; 
import Navbar from '../containers/navbar'; 

class Question extends Component { 
    constructor(props) { 
     super(props); 
     this.getClassName = this.getClassName.bind(this); 
    } 

    componentWillMount() { 
     this.props.setActiveQuestion(this.props.question_id); 
    } 

    componentWillReceiveProps(nextProps) { 
     if (this.props.question_id != nextProps.question_id) { 
      this.props.setActiveQuestion(nextProps.question_id); 
     } 
    } 

    setAnswer(answer_id) { 
     let question_id = this.props.question.id; 
     this.props.setQuestionAnswer(question_id, answer_id); 
    } 

    getClassName(answers, item_answer_id) { 

     let classes = []; 

     // find the answer for the active question 
     let answer_index = _.findIndex(answers, (answer) => { 
      return answer.question_id === this.props.question.id; 
     }); 

     // if there's no answer yet, skip class placement 
     if (answer_index === -1) { 
      return; 
     } 

     let answer = answers[answer_index]; 

     // Test cases 
     const isUserCorrect =() => { 
      return answer.answer_id == answer.correct_answer_id && item_answer_id == answer.correct_answer_id 
     } 

     const isUserAnswer =() => { 
      return answer.answer_id === item_answer_id; 
     } 

     const isCorrectAnswer =() => { 
      return item_answer_id == answer.correct_answer_id; 
     } 

     // Test and set the correct case classname for styling 
     if (isUserCorrect()) { 
      classes.push('user_correct_answer'); 
     } 

     if (isUserAnswer()) { 
      classes.push('user_answer'); 
     } 

     if (isCorrectAnswer()) { 
      classes.push('correct_answer'); 
     } 

     return classes.length > 0 ? classes.join(' ') : ''; 

    } 

    answersList() { 
     return this.props.question.answers.map((answer) => { 
      return <li className={ this.getClassName(this.props.answers, answer.id) } key={ answer.id } onClick={() => this.setAnswer(answer.id) }>{ answer.text }</li> 
     }); 
    } 

    render() { 
     return (
      <div> 
       <div className='question-container'> 
        <h2>{ this.props.question && this.props.question.question }</h2> 
        <ul> 
        { 
         this.props.question && 
         this.answersList() 
        } 
        </ul> 
       </div> 
       <Navbar /> 
      </div> 
     ); 
    } 
} 

function mapStateToProps(state, ownProps) { 
    return { 
     question_id: ownProps.params.question_id, 
     question: state.questions.active, 
     answers: state.answers 
    } 
} 

function matchDispatchToProps(dispatch) { 
    return bindActionCreators({ 
     setActiveQuestion: setActiveQuestion, 
     setQuestionAnswer: setQuestionAnswer 
    }, dispatch); 
} 

export default connect(mapStateToProps, matchDispatchToProps)(Question); 
関連する問題