# Redux Tutorial: Creating Pages

Step 1: Create redux-todolist/src/routes/AllTodos.js

We will now define a page that displays all the Todo items stored in our todos table.

Create a file redux-todolist/src/routes/AllTodos.js and paste the following code:


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

import actions from '../redux/actions';

import Todo from '../components/Todo';
import TodoForm from '../components/TodoForm';

import {
  Row,
  Col,
  Grid,
  Panel,
  Alert,
  PanelBody,
  PanelContainer,
} from '@sketchpixy/rubix';

@connect((state) => state)
export default class AllTodos extends React.Component {
  static fetchData(store) {
    return store.dispatch(actions.getTodos());
  }

  render() {
    let { todos, dispatch } = this.props;
    let { result, error } = todos;

    let errors = error ?
      (
        <Alert danger dismissible>
          {error.map(({ message }, i) => {
            return <div key={i}>{message}</div>
          })}
        </Alert>
      ) : null;

    return (
      <PanelContainer>
        <Panel>
          <PanelBody style={{padding: 0, paddingBottom: 25}}>
            <Grid>
              <Row>
                <Col xs={12}>
                  <h3>Todo List:</h3>

                  {errors}

                  <TodoForm dispatch={dispatch} actions={actions} />

                  {typeof result.map === 'function' && result.map((todo) => {
                    return <Todo key={todo._id} todo={todo} dispatch={dispatch} actions={actions} />;
                  })}
                </Col>
              </Row>
            </Grid>
          </PanelBody>
        </Panel>
      </PanelContainer>
    );
  }
}

We first import Todo and TodoForm components that we defined in the previous section.

We have also defined an AllTodos component class in the above code. This class defines a static fetchData() class method that is called before the AllTodos component is constructed. This gives us an opportunity to pre-load the component with data from the store. This is possible because we return a "promise". We return a dispatch which gets all Todo items.

However, you should note that static fetchData() is not called on page load but only when page navigates using the History API. The reason for this is that when the page loads it already has the data sent from the server. Therefore, there is no reason to re-fetch the data again.

The prop data is made available to the constructor of the AllTodos component. This is where we set the initial state of the component.

We then finally render the Todo form as well as the fetched todo items in the render() method.

Step 2: Create redux-todolist/src/routes/EditTodo.js

We will now define a page where we can edit a specific Todo item.

Create a file redux-todolist/src/routes/EditTodo.js and paste the following code:


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

import actions from '../redux/actions';

import {
  Row,
  Col,
  Grid,
  Form,
  Panel,
  Button,
  Checkbox,
  PanelBody,
  FormGroup,
  FormControl,
  ControlLabel,
  PanelContainer } from '@sketchpixy/rubix';

@withRouter
class EditTodoForm extends React.Component {
  editTodo(e) {
    e.preventDefault();

    let input = ReactDOM.findDOMNode(this.input);
    let todo = input.value;
    let completed = this.checkbox.checked;

    let { dispatch } = this.props;
    let { _id } = this.props.todo;

    dispatch(actions.updateTodo({
      _id,
      todo,
      completed
    })).then(() => {
      this.props.router.push('/');
    });
  }

  componentWillReceiveProps(newProps) {
    let input = ReactDOM.findDOMNode(this.input);
    input.value = newProps.todo.todo;
    this.checkbox.checked = newProps.todo.completed;
  }

  render() {
    let { todo, completed } = this.props.todo;

    return (
      <div>
        <Form onSubmit={::this.editTodo}>
          <FormGroup controlId='todoText'>
            <ControlLabel>Todo Text</ControlLabel>
            <FormControl type='text' placeholder='A todo item...' defaultValue={todo} ref={(input) => this.input = input} autoFocus />
          </FormGroup>
          <FormGroup controlId='todoComplete'>
            <Checkbox inputRef={(checkbox) => { this.checkbox = checkbox; }} defaultChecked={completed} >
              Mark as Completed
            </Checkbox>
          </FormGroup>
          <FormGroup>
            <Button type='submit' bsStyle='blue' onlyOnHover>Update Todo</Button>
          </FormGroup>
        </Form>
      </div>
    );
  }
}


@connect((state) => state)
export default class EditTodo extends React.Component {
  static fetchData(store, params) {
    return store.dispatch(actions.getTodo({
      _id: params.id
    }));
  }

  render() {
    let { todos, dispatch } = this.props;
    let { result } = todos;

    return (
      <PanelContainer>
        <Panel>
          <PanelBody style={{padding: 0, paddingBottom: 25}}>
            <Grid>
              <Row>
                <Col xs={12}>
                  <h3>Editing Todo Item:</h3>

                  <EditTodoForm todo={result} dispatch={dispatch} />
                </Col>
              </Row>
            </Grid>
          </PanelBody>
        </Panel>
      </PanelContainer>
    );
  }
}

The above code renders a form wherein you can edit your existing todo item's text and change it's completion state. The form is rendered in the EditTodoForm component which when submitted calls the editTodo method. This method dispatches an action called updateTodo along with the changed data { _id, todo, completed }. If the update is successful, the page is redirected back to the homepage.

Now that we have created our pages, let us define client-side routes to these pages.