Skip to content

saturnism/todo-react-umi-dva

Repository files navigation

Todo App with umi, dva

Introduction

This is my attempt to build a simple Todo app with umi, dva.

Setup

From Scratch

A sequence of steps that I did to create this Todo app.

Install umi

  1. Read [umi Getting Started guide]
  2. yarn global add umi

Bootstrap Todo application

  1. Create a new project directory: mkdir todo-umi-dva
  2. Bootstrap umi: yarn create umi
    1. For boilerplate type: choose app
    2. For use typescript: enter y
    3. For functionality do you want to enable, select everything(antd, dva, code splitting, dll, internationalization)
  3. Install dependencies: yarn install
  4. Run in dev mode: umi dev
  5. Visit via the browser: http://localhost:8000

Use Ant Design's CSS

  1. Edit src/layouts/index.css
    1. Import antd's CSS: @import '~antd/dist/antd.css'; (From Ant Design's Use in Typescript)
    2. Delete font-family related lines to use Ant Design's default.

Use Ant Design's Layout

  1. Edit src/layouts/index.tsx
    1. Import Ant components
      import { Layout, Menu, Breadcrumb } from 'antd';
      const { Header, Content, Footer } = Layout;
      
    2. Update render() to return Ant layout. Notice props.children is rendered within the Content block.

Create a Todo Model and Mock Service

  1. Create Todo directory: mkdir -p src/pages/todo
  2. Create a file to declare domain types: touch src/pages/todo/types.ts
    1. Create a Todo class. We'll come back to the Model file to wire up dva
  3. Create a Mock file to host the mock service: touch src/pages/todo/_mock.ts
    1. Mock /api/todos service (see source)
    2. Try it out:
      1. Post new Todo: curl -XPOST -H"Content-Type: application/json" -d'{"description" : "hello"}' localhost:8000/api/todos
      2. Get Todos: curl localhost:8000/api/todos
      3. Patch Todo: curl -XPATCH -H"Content-Type: application/json" -d'{"completed": true}' localhost:8000/api/todos/0

Create a Todo Service

  1. Create a Service file: touch src/pages/todo/service.ts
    1. Create TodoService, see source

Create the UI

  1. Create an index.tsx file: touch src/pages/todo/index.tsx
  2. Put in the basic frontend code:
  3. Refresh the page to see it: http://localhost:8080/todo

Wire up DVA

This is perhaps the most complicated thing... :/

  1. Create src/pages/todo/model.ts
    1. Set namespace to todos
    2. Create TodoState
    3. Initialize state as a type of TodoState
    4. Add a reducer
    5. Add effects. Each "effect" is later triggered by dispatch as type: "[namespace]/[effect name]", with payload
    6. Once an effect is completed, use yield put to trigger a reducer
  2. In src/pages/todo/index.tsx
    1. Declare an Props interface to access dispatch, loading, and data from dva
      interface ViewProps extends TodoState {
        dispatch: any;
        loading: boolean;
      }
      
    2. Use decoration to connect dva to component.
      @connect(({ todos, loading }) => ({
        todos,
        loading: loading.models.todos,
      }))
      
    3. What does @connect do? See this blog, and Proper Typing of react-redux Connected Components
    4. Where does loading coming from? See dva#1464

Link & Navigation

  1. In src/layouts/index.tsx
    1. Each <Menu> uses the path as key, e.g., <Menu.Item key="/">Home</Menu.Item>
    2. Use <Link> to navigate to URL, e.g., <Link to="/">Home</Link>
    3. In <Menu>, use location.pathname to select current item: <Menu ... defaultSelectedKeys={[location.pathname]}>...</Menu>

Page Title

  1. Read UmiJS - Router - Extending Routing by Annotation
  2. Page title can be set in the comment
    /**
     * title: Page Title
     */
    

Lint

  1. Read umi-lint instructions
  2. Add lint: yarn add umi-lint --dev
  3. Add to package.json
    "scripts": {
      ...
      "lint:umi": "umi-lint --tslint --prettier  src/",
      "precommit:umi": "umi-lint --staged --tslint --stylelint --prettier --fix"
      ...
    }
    
  4. Run: yarn lint:umi