如何使用reactjs和redux处理导航

时间:2016-06-25 09:54:30

标签: reactjs redux react-router react-router-redux

我正在使用react-router和react-router-redux来处理我页面上的导航。我需要以编程方式在组件内部更改我的URL。我试图使用这个方法:history.push来实现这个但是这个方法只是改变了url和与这个url相关联的组件没有更新。这个应用程序是一个简单的分页列表,所以当我切换到下一页时,url正在更改例如/ posts / 1到/ posts / 2但是视图没有更新。我认为这应该是这样的:

  1. 用户点击分页项目并单击处理程序称为传递 页码作为参数
  2. 在内部点击处理程序中,我调用history.push(/ posts / [page])。我可以 使用链接组件,但我希望能够在用户时执行某些操作 点击分页项目
  3. 我希望我的ObjectList组件将再次安装 componentDidMount将被调用
  4. 这可能不是最好的方法,所以我会很高兴提示 链接是硬编码的,特别是第一个参数 我的源代码:

    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>
          );
      }
    }
    

    减速器/ 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
    

    减速器/ 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 个答案:

答案 0 :(得分:2)

由于您没有更改组件树,因此不会再次装入ObjectList组件。它仍然是

<Home>
    <Results>
        <ObjectList />
    </Results>
</Home>

只有当您转到不同的路径并安装不同的根组件以便整个树都会改变时,它才会被重新安装。但你只是传递不同的道具。你需要使用

componentWillReceiveProps(nextProps) {
  this.props.fetchObjects(nextProps.params.pageNum);
}