LoginSignup
29
21

More than 3 years have passed since last update.

React×GoでTodoリスト作ってみた

Posted at

基本の復習も兼ねてTodoリストを作りました。
Reactでは、非同期でHTTP通信を行うためにaxiosを使っています。
Goでは、GORMechoを使っています。

React

Todo.js
import React from 'react';
import InputField from './InputField';
import List from './List';
import http from './http';

class Todo extends React.Component {
  constructor() {
    super();
    this.state = {
      text: "",
      lists: [],
    }
  }

  componentDidMount() {
    this.getTodoList();
  }

  getTodoList = () => {
    return http
      .get('/todo')
      .then((response) => {
        this.setState({ lists: response.data })
      })
      .catch(error => {
        console.log(error)
      })
  }

  handleChange = e => {
    this.setState({ text: e.target.value })
  }

  handleSubmit = () => {
    if (this.state.text === "") {
      return window.alert("入力してください")
    }
    return http
      .post('/todo', {
        text: this.state.text
      })
      .then(() => {
        this.setState({ text: "" });
        this.getTodoList();
      }
      )
      .catch(error => {
        console.log(error)
      })
  }

  handleDelete = (list) => {
    return http
      .delete(`/todo/${list.id}`)
      .then(() =>
        this.getTodoList()
      )
      .catch(error => {
        console.log(error)
      })
  }

  render() {
    return (
      <div className="todo">
        <div className="todo-title">
          <h1>Todo</h1>
        </div>
        <InputField
          text={this.state.text}
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
        />
        <List
          lists={this.state.lists}
          handleDelete={this.handleDelete}
        />
      </div>
    )
  }
}

export default Todo;
InputField.js
import React from 'react';

export default function InputField(props) {
  return (
    <div className="todo-input-field">
      <input placeholder="入力しよう" value={props.text} onChange={e => props.handleChange(e)}></input>
      <button onClick={props.handleSubmit}>保存</button>
    </div>
  )
}
http.js
import axios from 'axios';

const API_HOST = process.env.REACT_APP_API_HOST || 'http://localhost:〇〇〇〇';

const http = axios.create({
  baseURL: API_HOST,
});

export default http;

Go

main.go
package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"

    "パスに合わせて他のパッケージをimport"

    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

const defaultPort = "〇〇〇〇"

func port() string {
    p := os.Getenv("PORT")
    if p != "" {
        return ":" + p
    }
    return ":" + defaultPort
}

func main() {
    connStr := fmt.Sprintf(
        "%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True",
        "DBUSER",
        "DBPASSWORD",
        "DBPROTOCOL",
        "DBNAME",
    )

    db, err := gorm.Open("mysql", connStr)
    if err != nil {
        log.Fatal(err)
    }

    h := handler.New(db)

    server := &http.Server{
        Addr:    port(),
        Handler: h,
    }

    go func() {
        stop := make(chan os.Signal, 1)
        signal.Notify(stop, os.Interrupt)

        <-stop
        log.Println("Shutting down...")

        if err := server.Shutdown(context.Background()); err != nil {
            log.Println("Unable to shutdown:", err)
        }

        log.Println("Server stopped")
    }()

    log.Println("Listening on http://localhost" + port())
    if err := server.ListenAndServe(); err != http.ErrServerClosed {
        log.Fatal(err)
    }
}
handler.go
package handler

import (
    "net/http"

    "github.com/jinzhu/gorm"
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func New(db *gorm.DB) http.Handler {
    e := echo.New()
    e.Use(middleware.CORS())

    h := &handler{
        DB: db,
    }

    e.GET("/health", h.health)

    e.GET("/todo", h.getTodoLists)
    e.POST("/todo", h.createTodo)
    e.DELETE("/todo/:id", h.deleteTodo)

    return e
}

type handler struct {
    DB *gorm.DB
}

func (h *handler) health(c echo.Context) error {
    return c.JSON(http.StatusOK, map[string]string{"message": "OK"})
}
list.go
package handler

import (
    "net/http"
    "time"

    "github.com/labstack/echo"
)

type List struct {
    ID        uint      `json:"id"`
    Text      string    `json:"text"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

func (h *handler) getTodoLists(c echo.Context) error {
    var lists []List
    err := h.DB.Find(&lists).Error
    if err != nil {
        return err
    }

    return c.JSON(http.StatusOK, lists)
}

func (h *handler) createTodo(c echo.Context) error {
    var list List
    err := c.Bind(&list)
    if err != nil {
        return err
    }

    err = h.DB.Create(&list).Error
    if err != nil {
        return err
    }

    return c.JSON(http.StatusOK, list)
}

func (h *handler) deleteTodo(c echo.Context) error {
    var list List
    paramID := c.Param("id")

    err := h.DB.Where("id=?", paramID).Delete(&list).Error
    if err != nil {
        return err
    }

    return c.JSON(http.StatusOK, list)
}

本来であれば、type ~ struct 構造体を他のパッケージからインポートするのがベストな気がするのですが、importがうまくできなかったので、list.goにまとめて書きました。
この問題は解決したい、、、

DB

todoというデータベースの中にlistsテーブルがあり、中身は画像のようになってます。
スクリーンショット 2020-04-21 20.25.13.png

Todoリスト

スクリーンショット 2020-04-21 20.29.37.png

このような形で簡単なTodoリストが作成できると思います。

29
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
21