Перенаправление на новый внешний интерфейс перед рендерингом компонента React - PullRequest
0 голосов
/ 17 сентября 2018

Я хочу добавить функциональность в мое приложение для управления задачами, которое позволит пользователю нажать кнопку «Добавить задачу», которая создаст пустую задачу, обновит список задач и затем перенаправит к приложению редактирования маршрута этой задачи «/ задачи /: идентификатор». Это позволит одновременно отображать список задач «app / tasks» и страницу редактирования задачи «app / tasks /: id», находясь в «app / tasks /: id». Мой подход заключается в том, чтобы мой createTask({}) метод отправлял и действие createTask(task), и действие mountTask(taskId). mountTask(taskId) установит идентификатор недавно созданной задачи в мой список состояний списка задач, который будет использоваться для перенаправления. То, что я хочу сделать в моей TaskPage (контейнер для моего TaskList и TaskForm), это проверить, есть ли mountTaskId в состоянии ДО того, как он рендерится, а затем перенаправить соответственно. Первоначально я решил использовать componentWillReceiveProps, однако после прочтения документации React обнаружил, что это называется ПОСЛЕ рендеринга. Поскольку мой Маршрут отображается внутри TaskPage, перенаправление не будет иметь никакого влияния на Маршрут, так как он уже отображался до перенаправления. Каков наилучший способ обработать это перенаправление ДО того, как рендер будет вызван?

Внешние маршруты

TaskPage - "api/tasks"
TaskForm - "api/tasks/:id"

TaskPage

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

  componentDidMount() {
    this.fetchAllTasks();
  }

  componentWillReceiveProps(newProps) {
    if (newProps.mountedTaskId && this.props.mountedTaskId !== newProps.mountedTaskId) {
      this.props.history.push(RouteConstants.TASKS + `${newProps.mountedTaskId}`);
    }
  }

  render() {
    return (
      <div>
        <TaskList
          tasks={ this.props.tasks }
          createTask={ this.props.createTask }
          mountTask={ this.props.mountTask } />
        <Route
          path={ RouteConstants.TASKS_FORM }
          component={ TaskForm } />
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    tasks: Object.values(state.entities.tasks),
    mountedTaskId: state.ui.taskList.mountedTaskId
  };
}

function mapDispatchToProps(dispatch) {
  return {
    fetchAllTasks: () => {
      return dispatch(fetchAllTasks());
    },
    createTask: (task) => {
      return dispatch(createTask(task));
    },
    mountTask: (task) => {
      return dispatch(mountTask(task));
    },
    unmountTask: () => {
      return dispatch(unmountTask());
    }
  };
}

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

TaskList

export default class TaskList extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(type) {
    //Depending on type, create a blank task or section,
    //add it to the list, and redirect to that task/section's
    //edit route.

    return () => {
      switch (type) {
        case "task":
          this.props.createTask({});
          break;
        case "section":
        //Ignore for now...
          break;
        default:
          return null;
      }
    };
  }

  render() {
    const tasks = this.props.tasks.map( (task) => {
      return (
        <TaskItem task={ task } />
      );
    });

    return (
      <div>
        <div className="task-list-header">
          <button onClick={ this.handleClick("task") }>Add Task</button>
          <button onClick={ this.handleClick("section") }>Add Section</button>
        </div>
        <div className="task-list-container">
          <ul className="task-list">
            { tasks }
          </ul>
        </div>
      </div>
    );
  }
}

TaskForm

export default class TaskForm extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div>
        <p>Task Form</p>
      </div>
    );
  }
}
...