如何处理组件中的数据依赖性

时间:2018-09-25 18:48:06

标签: reactjs redux

我有一个显示项目列表的组件。我正在 componentDidMount()中从服务器获取数据。在reducer中,我选择第一项,设置一个 currentProject 变量。我想显示与此项目相关的任务。如何在获取任务之前确保已设置此变量?

项目

class Projects extends React.Component {
  constructor(props) {
    super(props);

    this.selectProject = this.selectProject.bind(this);
  }

  componentDidMount() {
    const { fetchByUserId, user } = this.props;
    fetchByUserId(user.id);
  }

  selectProject(e, project) {
    e.preventDefault();
    const { select } = this.props;
    select(project.id);
  }

  render() {
    const { items } = this.props;
    return (
    <div>
      <div className="projects">
        <ul>
          {_.map(items, (project) => (
            <li key={project.id} onClick={(e) => this.selectProject(e, project)}>
              {project.title}
            </li>
          ))}
        </ul>
      </div>    
      <div className="tasks">
          <Tasks />
      </div>
    </div>
    );
  }
}

const mapStateToProps = (state) => {
  const { user } = state.authentication;
  const { items, loading, error } = state.projects;
  return {
    user,
    items,
    loading,
    error
  };
};

export default connect(
  mapStateToProps,
  {
    fetchByUserId: projectsActions.fetchByUserId,
    select: projectsActions.select
  }
)(Projects);

任务

class Tasks extends React.Component {
  componentDidMount() {
    const { fetchTasksByProjectId, currentProject } = this.props;
    if (currentProject) {
      fetchTasksByProjectId(currentProject.id);
    }
  }

  renderTasks(tasks) {
    return (
      <div>
        {_.map(tasks, (task) => (
          <strong>{task.name}</strong>{" "}
          {task.description}
        ))}
      </div>
    );
  }

  render() {
    const { currentProject, tasks } = this.props;
    if (!tasks.length) {
      return <div>Loading...</div>;
    }
    return (
      <div>
        <h1 className="title">{currentProject.title}</h1>
        {this.renderTasks(tasks[currentProject.id])}
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  const { current: currentProject } = state.projects;
  const { items: tasks } = state.tasks;
  return {
    currentProject,
    tasks
  };
};

export default connect(
  mapStateToProps,
  {
    fetchTasksByProjectId: tasksActions.fetchByProjectId
  }
)(Tasks);

任务 componentDidMount()中,我试图仅在设置了变量的情况下获取数据,但我的组件永远不会再呈现。我想念什么,但是呢?

2 个答案:

答案 0 :(得分:3)

您必须将fetchTasksByProjectId链接到fetchByUserId操作调用。

使用伪代码:

getProjectByUserId
.then(projects => 
  getTasksByProjectId(projects[selectedProjectIndex])
)
.catch(error)

此外,从您的componentDidMount()中删除任务调用

//projects action call
export function getProjectByUserId(user_id) {
 return async(dispatch, getState) => {
    try {
      let projects = await projectsService.getProjectByUserId(user_id);
      dispatch({ type: "FETCH_PROJECTS", projects});
      /*Notice the call to another action in the response of the first action call, fyi the getState is used to access the id of current project in your redux state*/
      dispatch(getTasksByProjectId(projects[getState.currentProject.id])); 
    }
    catch (error) {
        return error;
    }
  };
}

//Tasks action call
export function getTasksByProjectId(project_id) {
 return async(dispatch, getState) => {
   try {
     const tasksData = await projectsService.getTasksByProjectId(project_id);
     dispatch({ type: "FETCH_CURRENT_TASKS", tasksData});
   } 
   catch (error) {
     return error; 
    }
 };
}

更详细的示例,可以更好地理解操作文件。这些服务是具有实际get请求的文件。调度调用将处理从调用返回的数据。

答案 1 :(得分:1)

我想我现在对问题的理解要好一些了,因此,我将按照以下方法做:不检查currentProject组件中是否存在Tasks,为什么不检查它并有条件地渲染{ Tasks组件中的{1}}?像这样:

Projects

这样,在填充... <div> { this.props.currentProject && <Tasks /> } </div> ... 之前,不会渲染/挂载Tasks,从而使this.props.currentProject中的检查变得多余,并允许您在不检查的情况下提取任务。