Bagikan melalui


Membuat aplikasi React di Visual Studio

Dalam tutorial ini, Anda membuat front-end React untuk aplikasi web daftar to-do menggunakan JavaScript dan Visual Studio 2022. Kode untuk aplikasi ini dapat ditemukan di ToDoJSWebApp.

Prasyarat

Pastikan untuk menginstal hal berikut:

  • Visual Studio 2022 atau yang lebih baru. Buka halaman unduhan Visual Studio untuk menginstalnya secara gratis.
  • npm (https://www.npmjs.com/), yang disertakan dengan Node.js.

Buat aplikasi React Daftar Tugas

  1. Di Visual Studio, pilih File > Proyek Baru > untuk membuka dialog Buat Proyek Baru, pilih templat React App JavaScript, lalu pilih Berikutnya.

    Cuplikan layar memperlihatkan memilih templat.

  2. Beri nama TodoWebApp proyek dan pilih Buat.

    Proyek JavaScript ini dibuat menggunakan perangkat baris perintah vite.

  3. Di Penjelajah Solusi, klik kanan folder src dan pilih Tambahkan > Folder Baru. dan buat folder baru bernama components.

    Ini adalah konvensi umum untuk menempatkan komponen dalam folder komponen, tetapi ini tidak diperlukan.

  4. Klik kanan folder baru, pilih Tambahkan > Item Baru, lalu pilih File Komponen React JSX dalam kotak dialog, beri nama TodoList, dan klik Tambahkan. Jika Anda tidak melihat daftar templat item, pilih Perlihatkan Semua Templat.

    Cuplikan layar memperlihatkan penambahan komponen JSX.

    Ini membuat file JSX baru di folder komponen.

  5. Buka komponen TodoList dan ganti konten default dengan yang berikut ini:

    function TodoList() {
      return (
        <h2>TODO app contents</h2>
      );
    }
    export default TodoList;
    

    Komponen ini menampilkan header, yang akan Anda ganti nanti.

    Selanjutnya, hubungkan komponen ini dalam aplikasi. App.jsx adalah komponen utama yang dimuatkan, yang mewakili daftar aplikasi to-do. Komponen ini digunakan dalam file main.jsx.

  6. Di Penjelajah Solusi, buka App.jsx, hapus semua impor dari bagian atas, dan hapus konten pernyataan pengembalian. File akan terlihat seperti berikut ini.

    function App() {
      return (
        <>
          <TodoList />
        </>
      );
    }
    export default App;
    
  7. Untuk menambahkan komponen TodoList, letakkan kursor Anda di dalam fragmen lalu ketik <TodoL RETURN atau <TodoL TAB. Ini menambahkan komponen. Ini mungkin juga secara otomatis menambahkan pernyataan impor.

    Cuplikan layar memperlihatkan penambahan komponen JSX ke aplikasi.

    Jika pernyataan impor tidak ditambahkan secara otomatis, tambahkan di awal file dengan mengetik import TodoL dan menekan tombol TAB .

    Selanjutnya, hapus file CSS.

  8. Buka App.css dan hapus semua konten.

  9. Buka Index.css dan hapus semua konten kecuali gaya untuk :root:

    :root {
      font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
      line-height: 1.5;
      font-weight: 400;
      color-scheme: light dark;
      color: rgba(255, 255, 255, 0.87);
      background-color: #242424;
    }
    

Menjalankan aplikasi

Pilih tombol Mulai Penelusuran Kesalahan dari toolbar atau tekan pintasan keyboard F5.

Aplikasi terbuka di jendela browser.

Cuplikan layar memperlihatkan aplikasi yang berjalan di browser.

Menambahkan fungsi daftar to-do ke aplikasi

Anda dapat membiarkan aplikasi berjalan. Saat Anda membuat perubahan, aplikasi secara otomatis memperbarui dengan konten terbaru menggunakan dukungan penggantian modul cepat Vite. Beberapa tindakan, seperti menambahkan folder atau mengganti nama file, mengharuskan Anda menghentikan penelusuran kesalahan lalu memulai ulang aplikasi, tetapi secara umum Anda dapat membiarkannya berjalan di latar belakang saat mengembangkan aplikasi Anda. Buka komponen TodoList.jsx sehingga kita dapat mulai menentukannya.

  1. Di Penjelajah Solusi, buka TodoList.jsx dan tambahkan UI yang diperlukan untuk menampilkan dan mengelola entri daftar to-do. Ganti konten dengan kode berikut:

    function TodoList() {
      return (
        <div>
          <h1>TODO</h1>
          <div>
            <input type="text" placeholder="Enter a task" required aria-label="Task text" />
            <button className="add-button" aria-label="Add task">Add</button>
          </div>
          <ol id="todo-list">
            <p>existing tasks will be shown here</p>
          </ol>
        </div>
      );
    }
    export default TodoList;
    

    Kode sebelumnya menambahkan kotak input untuk tugas to-do baru dan tombol untuk mengirimkan input. Selanjutnya, Anda menyambungkan tombol Tambahkan. Gunakan kait useState React untuk menambahkan dua variabel status, satu untuk tugas yang ditambahkan, dan satu lagi untuk menyimpan tugas yang ada. Untuk tutorial ini, tugas disimpan dalam memori dan bukan penyimpanan persisten.

  2. Tambahkan pernyataan impor berikut ke TodoList.jsx untuk mengimpor useState.

    import { useState } from 'react'
    
  3. Selanjutnya, gunakan hook tersebut untuk membuat variabel status. Tambahkan kode berikut dalam fungsi TodoList di atas pernyataan pengembalian.

    const [tasks, setTasks] = useState(["Drink some coffee", "Create a TODO app", "Drink some more coffee"]);
    const [newTaskText, setNewTaskText] = useState("");
    

    Ini menyiapkan dua variabel, tasks dan newTaskText, untuk data dan dua fungsi yang dapat Anda panggil untuk memperbarui variabel tersebut, setTasks dan setNewTasks. Saat nilai untuk variabel status diubah, React secara otomatis merender ulang komponen.

    Anda hampir siap untuk memperbarui TodoList.jsx untuk menampilkan item to-do sebagai daftar, tetapi ada konsep React penting untuk dipelajari terlebih dahulu.

    Di React, saat Anda menampilkan daftar item, Anda perlu menambahkan kunci untuk mengidentifikasi setiap item secara unik dalam daftar. Fitur ini dijelaskan secara mendalam dalam dokumentasi React di Rendering Daftar, tetapi di sini Anda akan mempelajari dasar-dasarnya. Anda memiliki daftar item to-do untuk ditampilkan, dan Anda perlu mengaitkan kunci unik untuk setiap item. Kunci untuk setiap item tidak boleh berubah, dan karena alasan ini Anda tidak dapat menggunakan indeks item dalam array sebagai kunci. Anda memerlukan ID yang tidak akan berubah sepanjang masa pakai nilai tersebut. Anda akan menggunakan randomUUID() untuk membuat ID unik untuk setiap item to-do.

  4. Buat todoList.jsx menggunakan UUID sebagai kunci untuk setiap item to-do. Perbarui todoList.jsx dengan kode berikut.

    import React, { useState } from 'react';
    
    const initialTasks = [
        { id: self.crypto.randomUUID(), text: 'Drink some coffee' },
        { id: self.crypto.randomUUID(), text: 'Create a TODO app' },
        { id: self.crypto.randomUUID(), text: 'Drink some more coffee' }
    ];
    
    function TodoList() {
        const [tasks, setTasks] = useState(initialTasks);
        const [newTaskText, setNewTaskText] = useState("");
    
        return (
            <article
                className="todo-list"
                aria-label="task list manager">
                <header>
                    <h1>TODO</h1>
                    <form className="todo-input" aria-controls="todo-list">
                        <input
                            type="text"
                            placeholder="Enter a task"
                            value={newTaskText} />
                        <button
                            className="add-button">
                            Add
                        </button>
                    </form>
                </header>
                <ol id="todo-list" aria-live="polite" aria-label="task list">
                    {tasks.map((task, index) =>
                        <li key={task.id}>
                            <span className="text">{task.text}</span>
                        </li>
                    )}
                </ol>
            </article>
        );
    }
    export default TodoList;
    

    Karena nilai ID ditetapkan di luar fungsi TodoList, Anda dapat yakin nilai tidak akan berubah jika halaman dirender ulang. Saat mencoba aplikasi dalam status ini, Anda akan melihat bahwa Anda tidak dapat mengetikkan elemen input todo. Ini karena elemen input terikat ke newTaskText, yang telah diinisialisasi ke string kosong. Untuk mengizinkan pengguna menambahkan tugas baru, Anda perlu menangani peristiwa onChange pada kontrol tersebut. Anda juga perlu menerapkan dukungan tombol Tambahkan.

  5. Tambahkan fungsi yang diperlukan segera sebelum pernyataan pengembalian dalam fungsi TodoList.

    function handleInputChange(event) {
        setNewTaskText(event.target.value);
    }
    
    function addTask() {
        if (newTaskText.trim() !== "") {
            setTasks(t => [...t, { id: self.crypto.randomUUID(), text: newTaskText }]);
            setNewTaskText("");
        }
        event.preventDefault();
    }
    

    Dalam fungsi handleInputChanged, nilai baru dari bidang input diteruskan melalui event.target.value, dan nilai tersebut digunakan untuk memperbarui nilai untuk variabel newTaskText dengan setNewTaskText. Dalam fungsi addTask, tambahkan tugas baru ke daftar tugas yang ada menggunakan setTasks dan atur ID item sebagai nilai UUID baru. Perbarui elemen input untuk menyertakan onChange={handleInputChange} dan perbarui tombol Tambahkan untuk menyertakan onClick={addTask}. Kode ini menghubungkan peristiwa ke fungsi yang menangani peristiwa tersebut. Setelah ini, Anda akan dapat menambahkan tugas baru ke daftar tugas. Tugas baru ditambahkan ke bagian bawah daftar. Agar aplikasi ini lebih berguna, Anda perlu menambahkan dukungan untuk menghapus tugas dan memindahkan tugas ke atas atau ke bawah.

  6. Tambahkan fungsi untuk mendukung penghapusan, pindah ke atas dan pindah ke bawah, lalu perbarui markup untuk menampilkan tombol untuk setiap tindakan. Tambahkan kode berikut dalam fungsi TodoList di atas pernyataan pengembalian.

    function deleteTask(id) {
        const updatedTasks = tasks.filter(task => task.id != id);
        setTasks(updatedTasks);
    }
    
    function moveTaskUp(index) {
        if (index > 0) {
            const updatedTasks = [...tasks];
            [updatedTasks[index], updatedTasks[index - 1]] = [updatedTasks[index - 1], updatedTasks[index]];
            setTasks(updatedTasks);
        }
    }
    
    function moveTaskDown(index) {
        if (index < tasks.length) {
            const updatedTasks = [...tasks];
            [updatedTasks[index], updatedTasks[index + 1]] = [updatedTasks[index + 1], updatedTasks[index]];
            setTasks(updatedTasks);
        }
    }
    

    Fungsi penghapusan menerima ID tugas, lalu menghapusnya dari daftar, dan menggunakan metode filter Array untuk membuat array baru yang tidak termasuk item yang dipilih, kemudian memanggil setTasks(). Dua fungsi lainnya mengambil indeks item karena pekerjaan ini khusus untuk pengurutan item. Baik moveTaskUp() maupun moveTaskDown() menggunakan penugasan penghancuran array untuk menukar tugas yang dipilih dengan tetangganya.

  7. Selanjutnya, perbarui tampilan untuk menyertakan tiga tombol ini. Perbarui pernyataan pengembalian untuk berisi yang berikut ini.

    return (
        <article
            className="todo-list"
            aria-label="task list manager">
            <header>
                <h1>TODO</h1>
                <form className="todo-input" onSubmit={addTask} aria-controls="todo-list">
                    <input
                        type="text"
                        required
                        autoFocus
                        placeholder="Enter a task"
                        value={newTaskText}
                        aria-label="Task text"
                        onChange={handleInputChange} />
                    <button
                        className="add-button"
                        aria-label="Add task">
                        Add
                    </button>
                </form>
            </header>
            <ol id="todo-list" aria-live="polite">
                {tasks.map((task, index) =>
                    <li key={task.id}>
                        <span className="text">{task.text}</span>
                        <button className="delete-button" onClick={() => deleteTask(task.id)}>
                            🗑️
                        </button>
                        <button className="up-button" onClick={() => moveTaskUp(index)}>
                            ⇧
                        </button>
                        <button className="down-button" onClick={() => moveTaskDown(index)}>
                            ⇩
                        </button>
                    </li>
                )}
            </ol>
        </article>
    );
    

    Anda telah menambahkan tombol yang diperlukan untuk melakukan tugas yang kami bahas sebelumnya. Anda menggunakan karakter Unicode sebagai ikon pada tombol. Dalam markup, ada beberapa atribut yang ditambahkan untuk mendukung penambahan beberapa CSS nanti. Anda mungkin juga memperhatikan penggunaan atribut aria untuk meningkatkan aksesibilitas, yang opsional namun sangat dianjurkan. Jika Anda menjalankan aplikasi, aplikasi akan terlihat seperti ilustrasi berikut.

    Cuplikan layar memperlihatkan aplikasi yang berjalan dan menampilkan daftar

    Anda sekarang dapat melakukan hal berikut di aplikasi web TODO.

    • Menambahkan tugas
    • Hapus tugas
    • Pindahkan tugas ke atas
    • Pindahkan tugas ke bawah

    Fungsi-fungsi ini berfungsi, tetapi Anda dapat merefaktor untuk membangun komponen yang dapat digunakan kembali untuk menampilkan item to-do. Markup untuk item to-do masuk ke komponen baru, TodoItem. Karena manajemen daftar tetap berada di komponen Todo, Anda dapat meneruskan panggilan balik ke tombol Hapus dan Pindahkan.

  8. Untuk memulai, klik kanan folder komponen di Penjelajah Solusi dan pilih Tambahkan > Item Baru.

  9. Dalam dialog yang terbuka, pilih File Komponen React JSX, beri nama TodoItem, dan pilih Tambahkan.

  10. Tambahkan kode berikut ke TodoItem.

    Dalam kode ini, Anda meneruskan tugas dan panggilan balik sebagai properti ke komponen baru ini.

    import PropTypes from 'prop-types';
    
    function TodoItem({ task, deleteTaskCallback, moveTaskUpCallback, moveTaskDownCallback }) {
        return (
            <li aria-label="task" >
                <span className="text">{task}</span>
                <button
                    type="button"
                    aria-label="Delete task"
                    className="delete-button"
                    onClick={() => deleteTaskCallback()}>
                    🗑️
                </button>
                <button
                    type="button"
                    aria-label="Move task up"
                    className="up-button"
                    onClick={() => moveTaskUpCallback()}>
                    ⇧
                </button>
                <button
                    type="button"
                    aria-label="Move task down"
                    className="down-button"
                    onClick={() => moveTaskDownCallback()}>
                    ⇩
                </button>
            </li>
        );
    }
    
    TodoItem.propTypes = {
        task: PropTypes.string.isRequired,
        deleteTaskCallback: PropTypes.func.isRequired,
        moveTaskUpCallback: PropTypes.func.isRequired,
        moveTaskDownCallback: PropTypes.func.isRequired,
    };
    
    export default TodoItem;
    

    Kode sebelumnya berisi markup dari komponen Todo dan di akhir kode tersebut Anda mendeklarasikan PropTypes. Alat peraga digunakan untuk meneruskan data dari komponen induk ke komponen turunan. Untuk informasi selengkapnya tentang Props, lihat Meneruskan Props ke Komponen – React. Karena fungsi hapus dan pindahkan sedang diteruskan sebagai panggilan balik, handler onClick perlu diperbarui untuk memanggil panggilan balik tersebut.

  11. Tambahkan kode yang diperlukan. Kode lengkap untuk TodoList yang menggunakan komponen TodoItem ditampilkan di sini.

    import React, { useState } from 'react'
    import TodoItem from './TodoItem'
    
    const initialTasks = [
        { id: self.crypto.randomUUID(), text: 'Drink some coffee' },
        { id: self.crypto.randomUUID(), text: 'Create a TODO app' },
        { id: self.crypto.randomUUID(), text: 'Drink some more coffee' }
    ];
    
    function TodoList() {
        const [tasks, setTasks] = useState(initialTasks);
        const [newTaskText, setNewTaskText] = useState("");
        function handleInputChange(event) {
            setNewTaskText(event.target.value);
        }
        function addTask() {
            if (newTaskText.trim() !== "") {
                setTasks(t => [...t, { id: self.crypto.randomUUID(), text: newTaskText }]);
                setNewTaskText("");
            }
            event.preventDefault();
        }
        function deleteTask(id) {
            const updatedTasks = tasks.filter(task => task.id !== id);
            setTasks(updatedTasks);
        }
        function moveTaskUp(index) {
            if (index > 0) {
                const updatedTasks = [...tasks];
                [updatedTasks[index], updatedTasks[index - 1]] = [updatedTasks[index - 1], updatedTasks[index]];
                setTasks(updatedTasks);
            }
        }
        function moveTaskDown(index) {
            if (index < tasks.length) {
                const updatedTasks = [...tasks];
                [updatedTasks[index], updatedTasks[index + 1]] = [updatedTasks[index + 1], updatedTasks[index]];
                setTasks(updatedTasks);
            }
        }
        return (
            <article
                className="todo-list"
                aria-label="task list manager">
                <header>
                    <h1>TODO</h1>
                    <form onSubmit={addTask} aria-controls="todo-list">
                        <input
                            type="text"
                            required
                            placeholder="Enter a task"
                            value={newTaskText}
                            aria-label="Task text"
                            onChange={handleInputChange} />
                        <button
                            className="add-button"
                            aria-label="Add task">
                            Add
                        </button>
                    </form>
                </header>
                <ol id="todo-list" aria-live="polite">
                    {tasks.map((task, index) =>
                        <TodoItem
                            key={task.id}
                            task={task.text}
                            deleteTaskCallback={() => deleteTask(task.id)}
                            moveTaskUpCallback={() => moveTaskUp(index)}
                            moveTaskDownCallback={() => moveTaskDown(index)}
                        />
                    )}
                </ol>
            </article>
        );
    }
    
    export default TodoList;
    

    Sekarang, komponen TodoItem digunakan untuk merender setiap item to-do. Perhatikan bahwa kunci diatur ke task.id, yang berisi nilai UUID untuk tugas tersebut. Saat menjalankan aplikasi, Anda seharusnya tidak melihat perubahan apa pun pada tampilan atau perilaku aplikasi karena Anda merefaktornya untuk menggunakan TodoItem.

    Sekarang setelah Anda memiliki semua fungsi dasar yang didukung, saatnya untuk mulai menambahkan beberapa gaya ke ini untuk membuatnya terlihat bagus. Mulailah dengan menambahkan tautan di Index.html untuk keluarga font, Inter, yang akan Anda gunakan untuk aplikasi ini. Dalam Index.html, ada beberapa item lain yang perlu dibersihkan. Secara khusus, judul harus diperbarui dan Anda ingin mengganti file vite.svg yang saat ini digunakan sebagai ikon.

  12. Perbarui Index.html dengan konten berikut.

    <!doctype html>
    <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <link rel="icon" type="image/svg+xml" href="/checkmark-square.svg" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>TODO app</title>
            <link href='https://fonts.googleapis.com/css?family=Inter' rel='stylesheet'>
            <script type="module" defer src="/src/main.jsx"></script>
        </head>
        <body>
        </body>
    </html>
    
  13. Edit file main.jsx untuk mengganti root dengan main saat memanggil createRoot.

    Kode lengkap untuk main.jsx ditampilkan di sini.

    import { StrictMode } from 'react'
    import { createRoot } from 'react-dom/client'
    import App from './App.jsx'
    import './index.css'
    
    createRoot(document.querySelector('main')).render(
        <StrictMode>
            <App />
        </StrictMode>,
    )
    

    Selain perubahan ini, file checkmark-square.svg ditambahkan ke folder publik. Ini adalah SVG dari gambar persegi tanda centang FluentUI, yang dapat Anda unduh secara langsung. (Ada paket yang dapat Anda gunakan untuk pengalaman yang lebih terintegrasi, tetapi itu di luar cakupan artikel ini.)

    Selanjutnya, perbarui gaya komponen TodoList.

  14. Di folder komponen, tambahkan file CSS baru bernama TodoList.css. Anda dapat mengklik kanan proyek dan memilih > Item Baru lalu pilih Lembar Gaya . Beri nama file TodoList.css.

  15. Tambahkan kode berikut ke TodoList.css.

    .todo-list {
        background-color: #1e1e1e;
        padding: 1.25rem;
        border-radius: 0.5rem;
        box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.3);
        width: 100%;
        max-width: 25rem;
    }
    
    .todo-list h1 {
        text-align: center;
        color: #e0e0e0;
    }
    
    .todo-input {
        display: flex;
        justify-content: space-between;
        margin-bottom: 1.25rem;
    }
    
    .todo-input input {
        flex: 1;
        padding: 0.625rem;
        border: 0.0625rem solid #333;
        border-radius: 0.25rem;
        margin-right: 0.625rem;
        background-color: #2c2c2c;
        color: #e0e0e0;
    }
    
    .todo-input .add-button {
        padding: 0.625rem 1.25rem;
        background-color: #007bff;
        color: #fff;
        border: none;
        border-radius: 0.25rem;
        cursor: pointer;
    }
    
    .todo-input .add-button:hover {
        background-color: #0056b3;
    }
    
    .todo-list ol {
        list-style-type: none;
        padding: 0;
    }
    
    .todo-list li {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0.625rem;
        border-bottom: 0.0625rem solid #333;
    }
    
    .todo-list li:last-child {
        border-bottom: none;
    }
    
    .todo-list .text {
        flex: 1;
    }
    
    .todo-list li button {
        background: none;
        border: none;
        cursor: pointer;
        font-size: 1rem;
        margin-left: 0.625rem;
        color: #e0e0e0;
    }
    
    .todo-list li button:hover {
        color: #007bff;
    }
    
    .todo-list li button.delete-button {
        color: #ff4d4d;
    }
    
    .todo-list li button.up-button,
    .todo-list li button.down-button {
        color: #4caf50;
    }
    
  16. Selanjutnya, edit todoList.jsx untuk menambahkan impor berikut di bagian atas file.

    import './TodoList.css';
    
  17. Refresh browser setelah menyimpan perubahan. Ini seharusnya meningkatkan tampilan aplikasi. Aplikasi akan terlihat seperti berikut ini.

    Cuplikan layar memperlihatkan versi akhir aplikasi yang berjalan.

    Sekarang Anda telah membuat aplikasi daftar to-do yang berfungsi yang menyimpan item to-do dalam memori. Dari titik ini, Anda dapat memperbarui aplikasi untuk menyimpan item to-do di localStorage/IndexedDb, atau mengintegrasikannya dengan database sisi server, atau backend lainnya, untuk penyimpanan yang lebih permanen.

Ringkasan

Dalam tutorial ini, Anda membuat aplikasi React baru menggunakan Visual Studio. Aplikasi ini terdiri dari daftar to-do, yang mencakup dukungan untuk menambahkan tugas, menghapus tugas, dan menyusun ulang. Anda membuat dua komponen React baru dan menggunakannya di seluruh tutorial ini.

Sumber daya