反应:如何在“页面”之间传递数据并处理页面重新加载?

时间:2018-08-15 05:36:00

标签: javascript reactjs react-router

我有一个React + Redux应用程序,该应用程序可以在供稿列表页面中为每个用户获取供稿,并能够在新页面中查看特定供稿项的更多详细信息(我将在下面的代码示例中进行解释)。有一个API可以获取供稿列表,但没有API可以获取特定供稿项目的详细信息。如何将数据从Feed列表页面传递到Feed详细信息页面?我将如何处理Feed详细信息页面的重新加载,或者如何处理用户可以为Feed详细信息页面添加书签并在以后访问的场景?

我的代码如下:

app.js

import React from 'react';
import {
  Route,
  Switch
} from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import Home from './homeComponent';
import Login from './loginComponent';
import FeedListing from './feedListingComponent';
import FeedDetails from './feedDetailsComponent';
import NoMatch from './NoMatchComponent';

const App = ({ history }) => {
  return (
    <ConnectedRouter history={history}>
        <Switch>
          <Route exact={true} path="/" component={Home} />
          <Route path="/login" component={Login} />
          <Route path="/feed/:profileId" component={FeedListing} />
          <Route path="/feed_details/:feedId" component={FeedDetails} />
          ... more routes
          <Route component={NoMatch} />
        </Switch>
    </ConnectedRouter>
  );
};

export default App;

feedListingComponent.js

import React, {Component} from 'react'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as feedActions from '../actions/feedActions';

class FeedListingComponent extends Component {
    constructor(props) {
        super();
    }

    componentDidMount() {
        const { profileId } = this.props.match.params;
        this.props.actions.getFeed(profileId); // Calls API to get feed for feed listing and contains all the data that would be required for the feed details in each feed item
    }

    render() {
        return (
            <div>
                ... code that loops through the getFeed response starts here
                    <a href="/feed_details/{feedId}">Go to details</a>
                ... code that loops through the getFeed response ends here
            </div>
        )
    }
}

function mapStateToProps(state) {
  return {
    feed: state.feed.get('feed')
  }
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(feedActions, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(FeedListingComponent);

feedDetailsComponent.js

import React, {Component} from 'react'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as feedActions from '../actions/feedActions';

class FeedDetailsComponent extends Component {
    constructor(props) {
        super();
    }

    componentDidMount() {
        ... some code here
    }

    render() {
        return (
            <div>
                ... need to show the feed details here
            </div>
        )
    }
}

function mapStateToProps(state) {
  return {
    ... some code here
  }
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(feedActions, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(FeedDetailsComponent);

我也在考虑调用API以在详细信息页面中获取供稿列表的供稿,这意味着我还需要将:profileId传递到供稿详细信息路由,以使供稿列表API能够正常工作:

<a href="/feed_details/{feedId}/{profileId}">Go to details</a>

然后我可以像这样通过feedId过滤响应:

const feedItem = feed.filter(function(feedItem){
    return feedItem.feedId == feedId;
});

但是,鉴于饲料可能包含成千上万种饲料,这根本不是一个最佳解决方案。

谁能建议一种更好,更优化的方式来处理我提到的所有情况。

更新:同时添加我的操作和化简代码。

feedActions.js

import * as actionTypes from './actionTypes';
import feedApi from '../api/feedApi';

export function getFeed(profileId) {
  return function(dispatch) {
    return feedApi.getFeed(profileId).then(response => {
      dispatch(getFeedSuccess(response.data));
    }).catch(error => {
      throw(error);
    });
  };
}

export function getFeedSuccess(response) {
  return { type: actionTypes.FEED, feed : response }
}

feedReducer.js

import Immutable from 'immutable';
import * as actionTypes from '../actions/actionTypes';

const initialState = Immutable.fromJS({
    feed: {}
});

export default function feedReducer(state = initialState, action) {
  switch(action.type) {
    case actionTypes.FEED:
      return state.setIn(['feed'], action.feed)
    default:
      return state;
  }
}

getFeed响应

[
    {
        feedId: 1,
        feedTitle: "Lorem ipsum",
        feedDescription: "Lorem ipsum"
    },
    {
        feedId: 2,
        feedTitle: "Lorem ipsum",
        feedDescription: "Lorem ipsum"
    },
    {
        feedId: 3,
        feedTitle: "Lorem ipsum",
        feedDescription: "Lorem ipsum"
    },
    ... and so on
]

1 个答案:

答案 0 :(得分:0)

不幸的是,如果不仔细检查每一项,就无法在数组中找到特定元素,这仅仅是数据结构的局限。

但是,我假设feedListing组件将不会显示数百万个项目的列表。您可能会希望在那里进行某种分页,对吗?

在这种情况下,您可以跟踪显示哪个页面,并从也存储在商店中的主数组中切出一个较小的数组。当用户转到下一页时,一个操作会从主数组中切出正确的部分并更新存储。然后,当用户选择这些项目之一并转到详细信息页面时,您只需过滤较小的数组即可找到正确的项目,因为您知道所选项目位于正确的页面上。

编辑:再次查看此内容,我个人将其结构化的方法是将其全部放到一页上,并在用户选择可见项时有条件地渲染详细信息组件。

class FeedListingComponent extends Component {
    constructor(props) {
        super();
        this.state = {
            selectedItem: null,
        }
    }

    componentDidMount() {
        const { profileId } = this.props.match.params;
        this.props.actions.getFeed(profileId); // Calls API to get 
feed for feed listing and contains all the data that would be required 
for the feed details in each feed item
    }

    displayDetails(item) {
        this.setState({
            selectedItem: item
        })
    }

    render() {
        if(this.state.selectedItem) {
            return (
                <FeedDetailsComponent
                    selectedItem={this.state.selectedItem}
                />
            );
        return (
            {this.props.feed.map(feedItem => (
               <ListItemComponent
                   onClick={() => this.displayDetails(feedItem)}
               />
            }
        );
    }
}

希望这是有道理的。您将需要在详细信息页面上使用某种“后退”按钮来将selectedItem设置为null,以便列表显示返回