React UI Tutorial
REACT Basic
React UI Tutorial: Buttons, Edit Boxes, Comboboxes, And Backend API Data
This tutorial focuses on the user interface part of React.
We shall learn:
– What a React component is
– How to create a button
– How to create an edit box
– How to create a combobox
– How to store UI values with React state
– How to send data to a backend API
– How to read data from a backend API
The examples use your Tank Monitor backend:
text
http://127.0.0.1:5000
1. What React Does
React helps you build a user interface with small pieces called components.
Example component:
jsx
function App() {
return (
Tank Monitor
);
}A component is just a JavaScript function that returns UI.
2. Important React Idea: State
State means data that can change while the page is open.
Examples:
– Text typed into an edit box
– Selected value in a combobox
– Data loaded from PostgreSQL through the backend API
– Loading or error messages
React uses ‘useState’ for this:
jsx
import { useState } from "react";
function App() {
const [tankName, setTankName] = useState("");
return (
<input
value={tankName}
onChange={(event) => setTankName(event.target.value)}
/>
);
}Meaning:
text
tankName
is the current value.
text
setTankName
changes the value.
3. Button Example
A React button looks like normal HTML, but you attach a JavaScript function with ‘onClick’ .
jsx
function App() {
function handleButtonClick() {
console.log("Button was pressed");
}
return (
<button onClick={handleButtonClick}>
Save
</button>
);
}
When the user presses the button, React runs:
javascript
handleButtonClick()
4. Edit Box Example
An edit box is usually an ‘<input>’
jsx
import { useState } from "react";
function App() {
const [operatorName, setOperatorName] = useState("");
return (
<input
type="text"
value={operatorName}
onChange={(event) => setOperatorName(event.target.value)}
/>
Current value: {operatorName}
);
}Important parts:
jsx
value={operatorName}The input displays the React state value.
jsx
onChange={(event) => setOperatorName(event.target.value)}When the user types, React updates the state.
This is called a controlled input.
5. Number Edit Box Example
For numbers:
jsx
import { useState } from "react";
function App() {
const [tankLevel, setTankLevel] = useState(0);
return (
<input
type="number"
value={tankLevel}
onChange={(event) => setTankLevel(Number(event.target.value))}
/>
Tank level: {tankLevel}
);
}‘event.target.value’ is normally text, so ‘Number(…)’ converts it to a number.
6. Date And Time Edit Box
For tank full and empty time:
JSX
import { useState } from "react";
function App() {
const [tankFullTime, setTankFullTime] = useState("");
return (
<input
type="datetime-local"
value={tankFullTime}
onChange={(event) => setTankFullTime(event.target.value)}
/>
{tankFullTime}
);
}The browser shows a date/time picker.
7. Combobox Example
In HTML, a combobox is a ‘
jsx
import { useState } from “react”;
function App() {
const [tankStatus, setTankStatus] = useState("full");
return (
<div>
<label>Tank status</label>
<select
value={tankStatus}
onChange={(event) => setTankStatus(event.target.value)}
>
<option value="full">Full</option>
<option value="empty">Empty</option>
<option value="running">Running</option>
</select>
<p>Selected status: {tankStatus}</p>
</div>
);
}The state value is:
javascript
tankStatus
The function that changes it is:
javascript
setTankStatus
8. Loading Data From Backend API
To read tank data from your backend:
text
GET http://127.0.0.1:5000/api/tank-times
React code:
jsx
import { useEffect, useState } from "react";
function App() {
const [tankRows, setTankRows] = useState([]);
const [error, setError] = useState("");
async function loadTankRows() {
try {
const response = await fetch("http://127.0.0.1:5000/api/tank-times");
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || "Could not load tank rows");
}
setTankRows(data);
} catch (error) {
setError(error.message);
}
}
useEffect(() => {
loadTankRows();
}, []);
return (
<main>
<h1>Tank Rows</h1>
{error && <p>{error}</p>}
<button onClick={loadTankRows}>
Refresh
</button>
<pre>{JSON.stringify(tankRows, null, 2)}</pre>
</main>
);
}Important:
jsx
useEffect(() => {
loadTankRows();
}, []);This runs once when the page opens.
9. Showing API Data In A Table
Instead of showing JSON, show a table:
jsx
function TankTable({ rows }) {
return (
<table>
<thead>
<tr>
<th>ID</th>
<th>Tank Full Time</th>
<th>Tank Empty Time</th>
<th>Duration Minutes</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.id}>
<td>{row.id}</td>
<td>{row.tankFullTime}</td>
<td>{row.tankEmptyTime || "Open"}</td>
<td>{row.durationMinutes ?? "Open"}</td>
</tr>
))}
</tbody>
</table>
);
}Use it like this:
JSX
<TankTable rows={tankRows} />
10. Sending Data To Backend API
To save a completed tank row, call:
text
POST http://127.0.0.1:5000/api/tank-times
React example:
jsx
import { useState } from "react";
function App() {
const [tankFullTime, setTankFullTime] = useState("");
const [tankEmptyTime, setTankEmptyTime] = useState("");
const [message, setMessage] = useState("");
async function saveTankTime() {
try {
const response = await fetch("http://127.0.0.1:5000/api/tank-times", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
tankFullTime: tankFullTime,
tankEmptyTime: tankEmptyTime
})
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error || "Could not save tank time");
}
setMessage("Saved successfully");
} catch (error) {
setMessage(error.message);
}
}
return (
<main>
<label>Tank full time</label>
<input
type="datetime-local"
value={tankFullTime}
onChange={(event) => setTankFullTime(event.target.value)}
/>
<label>Tank empty time</label>
<input
type="datetime-local"
value={tankEmptyTime}
onChange={(event) => setTankEmptyTime(event.target.value)}
/>
<button onClick={saveTankTime}>
Save
</button>
<p>{message}</p>
</main>
);
}
11. Form Submit Example
For real forms, prefer ‘onSubmit’.
jsx
function App() {
const [tankFullTime, setTankFullTime] = useState("");
const [tankEmptyTime, setTankEmptyTime] = useState("");
async function handleSubmit(event) {
event.preventDefault();
await fetch("http://127.0.0.1:5000/api/tank-times", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
tankFullTime,
tankEmptyTime
})
});
}
return (
<form onSubmit={handleSubmit}>
<input
type="datetime-local"
value={tankFullTime}
onChange={(event) => setTankFullTime(event.target.value)}
/>
<input
type="datetime-local"
value={tankEmptyTime}
onChange={(event) => setTankEmptyTime(event.target.value)}
/>
<button type="submit">
Save
</button>
</form>
);
}This line is important:
javascript
event.preventDefault();
It stops the browser from refreshing the page when the form is submitted.
12. Full UI Example
This example includes:
– Edit boxes
– Combobox
– Button
– Backend GET
– Backend POST
– Table
jsx
import { useEffect, useState } from "react";
function App() {
const [tankFullTime, setTankFullTime] = useState("");
const [tankEmptyTime, setTankEmptyTime] = useState("");
const [tankStatus, setTankStatus] = useState("completed");
const [rows, setRows] = useState([]);
const [message, setMessage] = useState("");
async function loadRows() {
try {
const response = await fetch("http://127.0.0.1:5000/api/tank-times");
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || "Could not load rows");
}
setRows(data);
} catch (error) {
setMessage(error.message);
}
}
async function saveRow(event) {
event.preventDefault();
try {
const response = await fetch("http://127.0.0.1:5000/api/tank-times", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
tankFullTime,
tankEmptyTime,
tankStatus
})
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error || "Could not save row");
}
setMessage("Saved successfully");
setTankFullTime("");
setTankEmptyTime("");
await loadRows();
} catch (error) {
setMessage(error.message);
}
}
useEffect(() => {
loadRows();
}, []);
return (
<main>
<h1>Tank Monitor</h1>
<form onSubmit={saveRow}>
<label>Tank full time</label>
<input
type="datetime-local"
value={tankFullTime}
onChange={(event) => setTankFullTime(event.target.value)}
/>
<label>Tank empty time</label>
<input
type="datetime-local"
value={tankEmptyTime}
onChange={(event) => setTankEmptyTime(event.target.value)}
/>
<label>Status</label>
<select
value={tankStatus}
onChange={(event) => setTankStatus(event.target.value)}
>
<option value="completed">Completed</option>
<option value="open">Open</option>
<option value="manual">Manual</option>
</select>
<button type="submit">Save</button>
</form>
<button onClick={loadRows}>Refresh</button>
<p>{message}</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>Full</th>
<th>Empty</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.id}>
<td>{row.id}</td>
<td>{row.tankFullTime}</td>
<td>{row.tankEmptyTime || "Open"}</td>
<td>{row.durationMinutes ?? "Open"}</td>
</tr>
))}
</tbody>
</table>
</main>
);
}
export default App;
13. How UI Data Links To Backend API
The UI does not talk directly to PostgreSQL.
The UI talks to Node.js:
javascript
fetch("http://127.0.0.1:5000/api/tank-times")Node.js talks to PostgreSQL:
javascript
pool.query("SELECT ... FROM tank_times")The flow is:
text
React UI
input values
|
v
fetch()
|
v
Node.js API
|
v
PostgreSQL
14. Common UI Pattern
Most React UI screens follow this pattern:
text
1. Create state variables
2. Show input controls
3. Update state when the user types or selects
4. Press a button
5. Send state values to backend API with fetch()
6. Show result or error message
7. Reload table data
Example:
JSX
const [name, setName] = useState("");
<input
value={name}
onChange={(event) => setName(event.target.value)}
/>
<button onClick={saveName}>Save</button>15. Quick Summary
Button:
jsx
Edit box:
JSX
<input value={name} onChange={(event) => setName(event.target.value)} />Combobox:
JSX
<select value={status} onChange={(event) => setStatus(event.target.value)}>
<option value="full">Full</option>
<option value="empty">Empty</option>
</select>GET from backend:
javascript
const response = await fetch("http://127.0.0.1:5000/api/tank-times");
const data = await response.json();POST to backend:
javascript
await fetch("http://127.0.0.1:5000/api/tank-times", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
tankFullTime,
tankEmptyTime
})
});