如何使用 reactjs 和 redux 处理导航
Posted
技术标签:
【中文标题】如何使用 reactjs 和 redux 处理导航【英文标题】:How to handle navigation using reactjs and redux 【发布时间】:2016-10-27 21:16:51 【问题描述】:我正在使用 react-router 和 react-router-redux 来处理我页面上的导航。我需要在组件内以编程方式更改我的 url。我试图使用这种方法:history.push 来实现这一点,但这种方法只是更改 url 并且与此 url 关联的组件不会更新。这个应用程序是带有分页的简单列表,所以当我切换到下一页时,url 会发生变化,例如 /posts/1 到 /posts/2 但视图没有更新。我认为这应该像这样工作:
-
用户单击分页项和单击处理程序称为传递
页码作为参数
在点击处理程序中,我调用了 history.push(/posts/[page])。我可以
使用链接组件,但我希望能够在用户做某事
点击分页项
我希望我的 ObjectList 组件将再次挂载,并且
componentDidMount 将被调用
这可能不是最好的方法,所以我会很高兴获得提示 链接是硬编码的,尤其是第一个参数 我的源代码:
client.js
import React from "react";
import ReactDOM from "react-dom";
import Router, Route, IndexRoute, browserHistory from "react-router";
import Results from "./views/Results";
import Home from "./views/Home";
import App from './components/App'
import Provider from 'react-redux';
import store, history from './store';
const app = document.getElementById('app');
ReactDOM.render(
<Provider store=store>
<Router history=history>
<Route path="/" component=App>
<IndexRoute component=Home />
<Route path="/:category/:cityId/:pageNum" component=Results></Route>
</Route>
</Router>
</Provider>,
app
);
store.js
import createStore, compose, applyMiddleware from 'redux'
import syncHistoryWithStore from 'react-router-redux'
import thunkMiddleware from 'redux-thunk'
import browserHistory from 'react-router'
import rootReducer from './reducers/index'
import createLogger from 'redux-logger'
import categories from './data/categories'
const loggerMiddleware = createLogger()
const defaultState =
categories,
resultsList:
objects: [],
counters: [],
isFetching: false
;
const store = createStore(
rootReducer,
defaultState,
compose (
applyMiddleware(
thunkMiddleware,
loggerMiddleware
),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
);
export const history = syncHistoryWithStore(browserHistory, store)
export default store
ObjectList.js
import React from "react";
import ObjectItem from "../components/ObjectItem"
import Loader from "../components/Loader"
import fetchObjects from "../actions/actionCreators";
import switchUrl from "../actions/actionCreators";
import PaginationPanel from "../components/PaginationPanel"
import classNames from 'classnames'
import push from 'react-router-redux';
import browserHistory from 'react-router'
import store, history from '../store';
export default class ObjectList extends React.Component
static defaultProps =
objectsPerPage: 20,
objectContainerClassName: 'object_list_items'
constructor(props)
super(props);
componentDidMount()
this.props.fetchObjects(this.props.params.pageNum);
paginateHandler(page)
this.props.history.push('/hotele/1/'+page)
render()
const resultsList = this.props
if(resultsList.items.length > 0)
const ObjectComponents = resultsList.items.map((item) =>
return <ObjectItem key=item.post_id ...item/>;
);
const paginationComponent =
<PaginationPanel
...this.props
pageNum=Math.ceil(resultsList.counters.allPosts/this.props.objectsPerPage)
pageClickedHandler=this.paginateHandler.bind(this)
currentPage=parseInt(this.props.params.pageNum)
/>
return (
<div className="object-lists">
<div className=this.props.objectContainerClassName>
<div>ObjectComponents</div>
</div>
paginationComponent
</div>
)
else if(!resultsList.isFetching || resultsList.items.length === 0)
return <Loader />;
Home.js
import React from "react"
import Link from "react-router"
const Home = React.createClass(
render()
return (
<div>
Strona główna <br />
<Link to=`/hotele/1/1`>Lista wyszukiwania</Link>
</div>
)
)
export default Home
Results.js
import React from "react";
import ObjectList from "../components/ObjectList"
import CategoryTabs from "../components/CategoryTabs"
import fetchObjects from "../actions/actionCreators"
export default class Results extends React.Component
constructor(props)
super(props);
render()
return (
<div>
<CategoryTabs ...this.props />
<ObjectList ...this.props />
</div>
);
reducers/index.js
import combineReducers from 'redux'
import routerReducer from 'react-router-redux'
import objects from './objects'
import categories from './categories'
const rootReducer = combineReducers(objects, categories, routing: routerReducer)
export default rootReducer
reducers/objects.js
function objects(state =
isFetching: false,
items: [],
counters: []
, action)
switch (action.type)
case 'RECEIVE_OBJECTS':
return Object.assign(, state,
isFetching: false,
items: action.objects.posts,
counters: action.objects.counters
)
default:
return state;
export default objects
app.js
import bindActionCreators from 'redux'
import connect from 'react-redux'
import * as actionCreators from '../actions/actionCreators';
import Main from '../components/Main';
function mapStateToProps(state)
return
resultsList: state.objects,
categories: state.categories
function mapDispatchToProps(dispatch)
return bindActionCreators(actionCreators, dispatch);
const App = connect(mapStateToProps, mapDispatchToProps)(Main);
export default App;
actionCreators.js
import fetch from 'isomorphic-fetch'
import push from 'react-router-redux';
function receiveObjects(objects, json)
return
type: 'RECEIVE_OBJECTS',
objects
function requestObject(pageNum)
return
type: 'REQUEST_OBJECTS',
pageNum
export function fetchObjects(pageNum)
return dispatch =>
dispatch(requestObject(pageNum));
let url = 'http://localhost:8080/posts?city=986283&type=hotel&page='+pageNum;
return fetch(url)
.then(response => response.json())
.then(json => dispatch(receiveObjects(json)));
【问题讨论】:
【参考方案1】:ObjectList 组件将不会再次挂载,因为您没有更改组件树。还是
<Home>
<Results>
<ObjectList />
</Results>
</Home>
只有当您转到不同的路线并安装不同的根组件时才会重新安装它,这样整个树都会改变。但你只是传递不同的道具。你需要使用
componentWillReceiveProps(nextProps)
this.props.fetchObjects(nextProps.params.pageNum);
【讨论】:
以上是关于如何使用 reactjs 和 redux 处理导航的主要内容,如果未能解决你的问题,请参考以下文章
react+redux 中如何通过请求动作处理中间件并触发成功动作?
如何正确地从 ReactJS + Redux 应用程序进行 REST 调用?
ReactJS:如何使用 Formik 处理图像/文件上传?
如何使用 MongoDB + NodeJS Express 向 ReactJS React Router 和 Redux 添加登录身份验证和会话?