การใช้ 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/