[英]react-router: get param from the router listen event fails
我發現嘗試使用react-router
router.listen(...)獲取route參數時失敗。 通過使用window.location.pathname.split('route /')[1],我可以獲得參數。 有小費嗎 ?
我一直在試圖找出原因。 到目前為止,我注意到它在第一次路由更改(URL更改)時失敗-我的意思是,通過使用,我的URL從/param/y
更改為/param/x
; 但該參數僅在再次單擊時可用。 我想這可能與我的動作或我的組件有關? 還是在響應生命周期中將偵聽器置於何處?
不知道我是在錯誤的生命周期方法中聲明事件偵聽器,還是; 正如我一直在想的那樣,我正在將路由傳遞給Store,但我認為此事件使用withRouter(Component)。 我想我需要使用redux的路由狀態。 我想
具有偵聽器的組件:
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 { 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 { 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;
我在@TryingToImprove反饋中找到了我非常感激的解決方案。 我以為我需要使用withRouter並將MyComponent包裝在其中,然后偵聽路由器的位置變化,但這顯然是錯誤的。 原因是因為我從Reducer存儲了路由參數,所以我可以在mapStateToProps期間隨時調用它。 更好的解釋是查看以下代碼:
function mapStateToProps(state, ownProps) {
return {
my_parameter_name: ownProps.params.my_parameter_name
}
}
export default connect(mapStateToProps)(MyComponent);
原始源代碼已更改,將如下所示:
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);
您可能不想看路由器,而是想看看withRotuer
。
它將使您可以訪問connect
。中的params對象。
withRouter(connect(function(state, props) {
return { question_id: props.params.question_id };
})(MyComponent)
然后您可以偵聽componentDidMount/componentWillMount
和componentWillReceiveProps(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);
}
}
現在,您的組件將無需了解react-router,並且具有更高的可重用性,加上當前的設置,您的組件將永遠不會停止偵聽可能導致問題的路由更改(因為缺少“ router.removeListner
”)。
在https://egghead.io/lessons/javascript-redux-using-withrouter-to-inject-the-params-into-connected-components?course=building-react-applications-with可以找到有關withRouter
的出色視頻-慣用的redux
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.