在React / Redux / Routerv4应用程序中加载数据的位置?

时间:2017-08-14 07:10:37

标签: reactjs redux react-router react-redux

我正在开发一个几乎完全按照以下路线运行的应用:/task/:taskId并且在/路线上无需呈现任何内容。相反,当您启动应用程序时,它应该重定向到任务。就像你打开懒散而且你在一个频道时一样。不在某些页面上说请选择一个频道。我无法弄清楚我想从数据库加载任务的位置。

现在,我有一个加载/的组件,并且在componentDidMount方法中,我从数据库加载任务。加载任务后,我会history.push重定向到数据库中任务数组中的第一个任务。

这一切都很有效,直到我被重定向到特定任务然后刷新页面。也就是说,如果我在/task/foobar并刷新页面,则应用程序不会加载任何内容,因为任务仅从/的数据库加载。

那么无论我在哪个页面上,确保我的数据都被加载的正确方法是什么?

编辑 - 添加一些代码供参考:

/routes.js - /使用Master.js和/ task /:taskId使用TaskPage.js

import React from 'react';
import { Switch, Route } from 'react-router';
import App from './containers/App';
import Master from './containers/Master';
import TaskPage from './containers/TaskPage';

export default () => (
  <App>
    <Switch>
      <Route exact path="/" component={Master} />
      <Route path="/task/:taskId" component={TaskPage} />
    </Switch>
  </App>
);

/containers/Master.js - loadTasks是将任务数据传递给任务reducer的动作创建者。还返回从本地nedb数据库加载后解析为任务数据的promise。

import React, { Component } from 'react';
import { connect } from 'react-redux';

import { loadTasks } from '../actions/tasks';

class Master extends Component {
  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    this.props.loadTasks()
    .then(tasks => {
      const id = tasks[Object.keys(tasks)[0]]._id;
      this.props.history.push(`/task/${id}`);
      return true;
    })
    .catch(e => {
      console.log('ERROR', e);
    });
  }

  render() {
    return (
      <div>
        {this.props.children}
      </div>
    );
  }
}

const mapStateToProps = (props, ownProps) => ({
  taskId: ownProps.taskId
});

export default connect(mapStateToProps, {
  loadTasks
})(Master);

/containers/TaskPage.js - 这里看不多。只需将道具传递给包裹的组件任务,只要应用程序加载/第一次就可以正常呈现。如果您直接点击/ task /:taskId,则无法加载任何内容,因为数据库中的任务数据仅在/

处加载到redux商店
import { connect } from 'react-redux';
import Task from '../components/Task';

const mapStateToProps = ({ tasks }, { match: { params: { taskId } } }) => ({
  tasks,
  taskId
});

export default connect(mapStateToProps)(Task);

1 个答案:

答案 0 :(得分:0)

编辑 - 我已经删除了我的旧答案,支持我认为基于我已经完成的一些挖掘的更好方法。

我在一些地方看到过Dan Abramov的一些事情让我觉得他在组件内部(不是容器)进行数据获取,他会使用componentDidMount生命周期方法来做所以。我唯一不确定的是如何最好地决定应用程序是否应显示加载状态。

在Dan和其他人中&#39;例子,他们只是检查state.loading是否为false并且state.items.length是否为0.这仅适用于您始终期望项目具有数据的情况。但在我的情况下,当你第一次启动应用程序时,你将没有数据,所以检查0长度并不是真的有用。相反,我已经向该州添加了一个initLoad属性。

如果有更好的方法,我可以采取其他方式处理这个问题。

<强> routes.js

import React from 'react';
import { Switch, Route } from 'react-router';
import App from './containers/App';
import TaskPage from './containers/TaskPage';

export default () => (
  <App>
    <Switch>
      <Route exact path="/" component={TaskPage} />
      <Route path="/task/:taskId" component={TaskPage} />
    </Switch>
  </App>
);

<强> TaskPage.js

import { connect } from 'react-redux';
import { withRouter } from 'react-router';

import { loadTasks } from '../actions/tasks';

import Task from '../components/Task';

const mapStateToProps = ({ tasks }, { match: { params: { taskId } } }) => ({
  tasks,
  taskId,
});

const mapDispatchToProps = dispatch => ({
  loadTasks: () => dispatch(loadTasks())
});

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Task));

<强> Task.js

import React, { Component } from 'react';

import type { tasksType } from '../reducers/tasks';

import SidebarContainer from '../containers/SidebarContainer';

class Task extends Component {
  props: {
    loadTasks: () => any,
    initForm: () => any,
    taskId: string,
    tasks: tasksType,
    history: any
  };

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    this.props.loadTasks()
    .then(tasks => {
      const taskId = this.props.taskId;

      if (!taskId) {
        const id = tasks[Object.keys(tasks)[0]]._id;
        this.props.history.push(`/task/${id}`);
      }

      return true;
    })
    .catch(e => {
      console.log('ERROR', e);
    });
  }

  render() {
    const { tasks, taskId, initForm } = this.props;

    if (!tasks.initLoad || (tasks.loading && Object.keys(tasks.items).length < 1)) {
      return <div>Loading</div>;
    }

    return (
      <div id="wrapper">
        <SidebarContainer taskId={taskId} />
        <div id="main">
          <div id="group-details">
            {tasks.initLoad && Object.keys(tasks.items).length > 0 ?
              (<div>Task details would go here...</div>) :
              (<div>Please create a task</div>)
            }
          </div>
        </div>
      </div>
    );
  }
}

export default Task;