การใช้ React กับ Go Fiber


React เป็น JavaScript library ที่ใช้สำหรับสร้าง user interface ที่ให้เราสามารถเขียนโค้ดในการสร้าง UI ที่มีความซับซ้อนแบ่งเป็นส่วนเล็กๆออกจากกันได้ ซึ่งแต่ละส่วนสามารถแยกการทำงานออกจากกันได้อย่างอิสระ และทำให้สามารถนำชิ้นส่วน UI เหล่านั้นไปใช้ซ้ำได้อีก เรียนรู้การใช้งาน React เบื้องต้นที่ พัฒนาเว็บด้วย React สำหรับผู้เริ่มต้น โดย KongRuksiam Official

React นิยมใช้งานเป็น Front-End คือ ส่วนหน้าเว็บไซต์ที่สามารถมองเห็นได้ในบราวเซอร์ ส่วนที่ผู้ใช้เว็บจะเห็น หรือพูดง่าย ๆ ว่าส่วนที่เขียนขึ้นด้วย HTML / CSS / Javascript นั่นเอง แต่ถ้าส่วนที่เป็นส่วนจัดการข้อมูล ที่เน้นโค้ดด้านการประมวลผลของเว็บไซต์อย่างเช่น การสร้าง Go Fiber RESful API เราจะเรียกว่า Back-End

ข้อกำหนดเบื้องต้น


ในการปฏิบัติตามบทความนี้ ต้องปฏิบัติตามบทความ การสร้าง Go Fiber RESful API มาก่อน


เปิดโปรแกรม Visual Studio Code


เปิดโปรแกรม VS Code ไปที่ File -> Open Folder… สร้างโฟลเดอร์ Projects ภายใน %USERPROFILE%


ปรับโหมดการใช้งานของ Terminal โดยไปที่ Terminal -> New Terminal


เปลี่ยนจาก PowerShell เป็น Command Prompt


Create a New React App

ติดตั้งตามขั้นลิงค์ https://reactjs.org/docs/create-a-new-react-app.html


สร้างโปรเจคโดยใช้คำสั่ง

npx create-react-app react-todos


Customize Theme


เราจะใช้ antd ภายในและแก้ไขการกำหนดค่า webpack สำหรับความต้องการที่กำหนดเอง

https://ant.design/docs/react/use-with-create-react-app


ใช้คำสั่ง เข้าไปภายในโฟลเดอร์ react-todos

cd react-todos


ติดตั้ง antd ด้วยคำสั่ง

npm install antd --save


แก้ไข ไฟล์ App.css


โดยแก้ไขจากโค้ดด้านบน เป็นตามโค้ดด้านล่าง

@import '~antd/dist/antd.css';


แก้ไข ไฟล์ App.js


import { Button } from 'antd';

<Button type="primary">Button</Button>


เริ่มต้นการทำงาน React ด้วยคำสั่ง

npm start


(อาจจะใช้เวลา … 2-3 นาที)


ที่เว็บบราวเซอร์หลัก ในตัวอย่าง เป็น Google Chrome จะแสดง URL http://localhost:3000/ และเห็นปุ่ม Button อยู่บนหน้าจอของคุณ

คลิกขวาที่ปุ่ม -> Inspect

สังเกต ที่ Button จะมี CSS ของ antd คือ class=”ant-btn ant-btn-primary”


Build Project Structure


สร้างโฟลเดอร์ services และ โฟลเดอร์ components ภายในโฟลเดอร์ src


สร้างไฟล์ todoService.js ภายในโฟลเดอร์ src


สร้างไฟล์ TodoForm.jsx , TodoItem.jsx , TodoList.css , TodoList.jsx และ TodoTab.jsx ภายในโฟลเดอร์ components

JSX ย่อมาจาก ( JavaScript Syntax eXtension) ซึ่งหมายถึงส่วนเสริมของ Javascript รูปแบบของ JSX นั้นเหมือนกับ HTML เป็นอย่างมาก แต่สิ่งนึงที่เห็นได้ชัดคือจะเห็นการเขียนโค้ดในลักษณะนี้ในอยู่ในไฟล์ Javascript แทนที่จะเป็นไฟล์ HTML


Build Todo Service


ส่วนที่หนึ่งของการสร้างบริการนี้ เราจะมี URL พื้นฐานของเรา เริ่มจากฐาน URL คงที่กันก่อน

สร้างไฟล์ .env ภายในโฟลเดอร์ react-todos เขียนโค้ดดังนี้

REACT_APP_API_URL=http://localhost:8000


ไปที่ไฟล์ todoService.js เขียนโค้ดดังนี้

const baseUrl =  `${process.env.REACT_APP_API_URL}/todos`;

export const loadTodos = () => {
    return fetch(baseUrl).then((res) => res.json());
}

export const getTodo = (id) => {
    return fetch(`${baseUrl}/${id}`).then((res) => res.json());
} 

export const createTodo = (todo) => {
    return fetch(baseUrl, {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            title: todo.title,
            completed: todo.completed
        }),
    }).then((res) => res.json());
}; 

export const updateTodo = (todo) => {
    return fetch(`${baseUrl}/${todo.id}`, {
        method: "PUT",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            id: todo.id,
            title: todo.title,
            completed: todo.completed
        }),
    }).then((res) => res.json());
}; 

export const deleteTodo = (id) => {
    return fetch(`${baseUrl}/${id}` , {
        method: "DELETE",
    }).then(res => res.json());
}



Create Todo Form



ไปที่ไฟล์ TodoForm.jsx  เขียนโค้ดดังนี้

import React from "react";
import { Form, Row, Col, Button, Input } from 'antd'
import {PlusCircleFilled} from '@ant-design/icons';

const TodoForm = ({onFormSubmit}) => {
    const [form] = Form.useForm();

    const onFinish = () => {
        onFormSubmit({
            title: form.getFieldValue('title'),
            completed: false

        });
        console.log(form.getFieldValue('title'));

        form.resetFields();
    }

    return(
        <Form
            form={form}
            onFinish={onFinish}
            Layout="horizontal"
            className="todo-form">
            <Row gutter={20}>
                <Col xs={24} sm={24} md={17} lg={19} xl={20}>
                    <Form.Item
                    name={'title'}
                    rules={[{ required: true, massage: 'This field is required'}]}>
                    <Input placeholder="what needs to be done?"/>
                    </Form.Item>
                </Col>
                <Col xs={24} sm={24} md={7} lg={5} xl={4}>
                    <Button type="primary" htmlType="submit" block>
                    <PlusCircleFilled />
                        Add Todo
                    </Button>
                </Col>
            </Row>
        </Form>
    );
}

export default TodoForm;



Build Todo Item


ไปที่ไฟล์ TodoItem.jsx เขียนโค้ดดังนี้

import React, {useState} from 'react';
import { Tooltip, Tag, List, Button, Popconfirm, Switch } from 'antd';
import { CloseOutlined, CheckOutlined } from '@ant-design/icons';

const Todo = ({todo, onTodoRemoval, onTodoToggle}) => {

    return (
        <List.Item
            actions={[
                <Tooltip
                title={todo.completed ? 'Mark as uncomleted' : 'Mark as comleted'}>
                <Switch
                    checkedChildren={<CheckOutlined/>}
                    unCheckedChildren={<CloseOutlined />}
                    onChange={() => onTodoToggle(todo)}
                    defaultChecked={todo.completed}
                />
                </Tooltip>,
                <Popconfirm
                tilte={'Are you sure you want to delete?'}
                onConfirm={() => {
                    onTodoRemoval(todo);
                }}>   
                    <Button className="remove-todo-button" type="primary" danger>
                        x
                    </Button> 
                </Popconfirm>
            ]}
            className="list-item"
            key={todo.id}
            >
            <div className="todo-item">
                <Tag color={todo.completed ? 'cyan' : 'red'} className="todo-tag"> 
                    {todo.title}
                </Tag>
            </div>
        </List.Item>
    )
}

export default Todo;


Build TodoTab


ไปที่ไฟล์ TodoTab.jsx เขียนโค้ดดังนี้

import React, {useEffect} from 'react';
import { Tabs, Layout, Row, Col, List } from 'antd';
import TodoItem from './TodoItem';

const TodoTab = ({ todos, onTodoRemoval, onTodoToggle }) => {
    return (
        <><List
            locale={{ emptyText: "There's nothing to do :(", }}
            dataSource={todos}
            renderItem={(todo) => (
                <TodoItem
                    todo={todo}
                    onTodoToggle={onTodoToggle}
                    onTodoRemoval={onTodoRemoval}
                />
            )}  
            pagination={{
                position: 'bottom',
                pageSize: 10,
            }}             
        /></>
    )
}

export default TodoTab;



Create TodoList State


ไปที่ไฟล์ TodoList.jsx เขียนโค้ดดังนี้

import React, {useEffect, useState, useCallback } from 'react';
import { Tabs, Layout, Row, Col, Input, message } from 'antd';
import './TodoList.css';
import TodoTab from './TodoTab';
import TodoForm from './TodoForm';
import { createTodo, deleteTodo, loadTodos, updateTodo} from '../services/todoService';
const { TabPane } = Tabs;
const { Content } = Layout;

const TodoList = () => {
    const [refreshing, setRefreshing] = useState(false);
    const [todos, setTodos] = useState([]);
    const [activeTodos, setActiveTodos] = useState([]);
    const [completedTodos, setCompletedTodos] = useState();

    const handleFormSubmit = (todo) => {
        console.log('Todo to create', todo);
        createTodo(todo).then(onRefresh());
        message.success('Todo added!');
    }

    const handleRemoveTodo = (todo) => {
        deleteTodo(todo.id).then(onRefresh());
        message.warn('Todo removed');
    }

    const handleToggleTodoStatus = (todo) => {
        todo.completed = !todo.completed;
        updateTodo(todo).then(onRefresh());
        message.info('Todo status updated!');
    }

    const refresh = () => {
        loadTodos()
            .then(json => {
                setTodos(json);
                setActiveTodos(json.filter(todo => todo.completed === false));
                setCompletedTodos(json.filter(todo => todo.completed === true));
            }).then(console.log('fetch completed'));
    }

    const onRefresh = useCallback( async () => {
        setRefreshing(true);
        let data = await loadTodos();
        setTodos(data);
        setActiveTodos(data.filter(todo => todo.completed === false));
        setCompletedTodos(data.filter(todo => todo.completed === true));
        setRefreshing(false);
        console.log('Refresh state', refreshing);
    }, [refreshing]);

    useEffect(() => {
        refresh();
    }, [onRefresh])

    return (
      <Layout className="layout">
        <Content style={{ padding: '0 50px'}}>
            <div className="todolist">
              <Row>
                  <Col span={14} offset={5}>
                    <h1>Conebrains Todos</h1>
                    <TodoForm onFormSubmit={handleFormSubmit} />
                    <br />
                    <Tabs defaultActiveKey="all">
                      <TabPane tab="ALL" key="all">
                        <TodoTab
                          todos={todos}
                          onTodoToggle={handleToggleTodoStatus}
                          onTodoRemoval={handleRemoveTodo}
                        />
                      </TabPane>

                      <TabPane tab="Active" key="active">
                        <TodoTab
                          todos={activeTodos}
                          onTodoToggle={handleToggleTodoStatus}
                          onTodoRemoval={handleRemoveTodo}
                        />
                      </TabPane>

                      <TabPane tab="Complete" key="complete">
                        <TodoTab
                          todos={completedTodos}
                          onTodoToggle={handleToggleTodoStatus}
                          onTodoRemoval={handleRemoveTodo}
                        />
                      </TabPane>
                    </Tabs>
                  </Col>
              </Row>
            </div>
        </Content>
      </Layout>
    );  
}

export default TodoList;


ไปที่ไฟล์ TodoList.css เขียนโค้ดดังนี้

.todolist {
    margin: 24px;
    padding: 24px;
    background: #fff;
}


เปิดการทำงาน แอป Go Fiber RESful API


เปิดการทำงานของแอป Go Fiber RESful API ที่ได้สร้างไว้ก่อนหน้านี้

go run main.go


แก้ไข ไฟล์ App.js ของ React


แก้ไข ไฟล์ App.js ของ React ตามโค้ดด้านล่าง

import './App.css';
import TodoList from './components/TodoList'

function App() {
  return (
    <div className="App">
      <TodoList/>
    </div>
  );
}

export default App;


แล้วจึงเริ่มต้นการทำงาน React ด้วยคำสั่ง

npm start


ผลลัพธ์การทำงาน


ทดสอบเพิ่มข้อมูล Add todo -> คลิกที่ปุ่ม Add todo

จะพบข้อมูล Add todo เพิ่มเข้ามา


ทดสอบ Update


ทดสอบ delete (ลบข้อมูล)

credit : https://www.udemy.com/course/build-a-todolist-with-go-golang-fiber-and-react/

Leave a Reply

Your email address will not be published. Required fields are marked *