Sdílet prostřednictvím


Vytvořte aplikaci React v prostředí Visual Studio

V tomto kurzu vytvoříte front-end Reactu pro webovou aplikaci se seznamem to-do pomocí JavaScriptu a sady Visual Studio 2022. Kód pro tuto aplikaci najdete v ToDoJSWebApp.

Požadavky

Nezapomeňte nainstalovat následující:

Vytvoření aplikace React ToDo List

  1. V sadě Visual Studio vyberte Soubor > Nový > Projekt pro otevření dialogového okna Vytvořit nový projekt, vyberte šablonu React App JavaScript a pak zvolte Další.

    Snímek obrazovky znázorňující výběr šablony

  2. Pojmenujte projekt TodoWebApp a vyberte Vytvořit.

    Tím se vytvoří projekt JavaScriptu pomocí nástroje příkazového řádku vite.

  3. V Průzkumníku řešení klikněte pravým tlačítkem myši na složku src a zvolte Přidat > Novou složku. a vytvořte novou složku s názvem components.

    Je to běžná konvence pro umístění součástí do složky komponent, ale nevyžaduje se to.

  4. Klikněte pravým tlačítkem myši na novou složku, vyberte Přidat > novou položku a v dialogovém okně zvolte React JSX Component File , pojmenujte ji TodoLista klikněte na Přidat. Pokud seznam šablon položek nevidíte, vyberte Zobrazit všechny šablony.

    Snímek obrazovky znázorňující přidání komponenty JSX

    Tím se vytvoří nový soubor JSX ve složce komponent.

  5. Otevřete komponentu TodoList a nahraďte výchozí obsah následujícím kódem:

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

    Tato komponenta zobrazí hlavičku, kterou později nahradíte.

    Dále tuto komponentu v aplikaci propojte. Komponenta App.jsx je hlavní součást, která je načtená a představuje aplikaci seznamu to-do. Tato komponenta se používá v souboru main.jsx.

  6. V Průzkumníku řešení otevřete App.jsx, odeberte všechny importy z horní části a vymažte obsah příkazu return. Soubor by měl vypadat takto.

    function App() {
      return (
        <>
          <TodoList />
        </>
      );
    }
    export default App;
    
  7. Chcete-li přidat komponentu TodoList, umístěte kurzor do fragmentu a zadejte <TodoL RETURN nebo <TodoL TAB. Tím se přidá komponenta. Může také automaticky přidat příkaz importu.

    snímek obrazovky znázorňující přidání komponenty JSX do aplikace

    Pokud se příkaz importu nepřidá automaticky, přidejte ho na začátek souboru zadáním import TodoL a stisknutím klávesy TAB .

    V dalším kroku vymažte soubory CSS.

  8. Otevřete App.css a odstraňte veškerý obsah.

  9. Otevřete Index.css a odeberte veškerý obsah kromě stylů pro :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;
    }
    

Spuštění aplikace

Na panelu nástrojů vyberte tlačítko Spustit ladění nebo stiskněte klávesovou zkratku F5.

Aplikace se otevře v okně prohlížeče.

Snímek obrazovky zobrazující aplikaci spuštěnou v prohlížeči

Přidání funkcí seznamu to-do do aplikace

Aplikaci můžete nechat spuštěnou. Při provádění změn se aplikace automaticky aktualizuje s nejnovějším obsahem pomocí podpory nahrazení horkého modulu Vite. Některé akce, jako je přidání složek nebo přejmenování souborů, vyžadují, abyste zastavili ladění a pak aplikaci restartovali, ale obecně ji můžete nechat spuštěnou na pozadí při vývoji aplikace. Otevřete komponentu TodoList.jsx, abychom ji mohli začít definovat.

  1. V Průzkumníku řešení otevřete TodoList.jsx a přidejte uživatelské rozhraní potřebné k zobrazení a správě položek seznamu to-do. Nahraďte obsah následujícím kódem:

    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;
    

    Předchozí kód přidá vstupní pole pro nový to-do úkol a tlačítko pro odeslání vstupu. Nyní propojte tlačítko Přidat. Pomocí funkce useState React hook přidejte dvě stavové proměnné, jednu pro úkol, který se přidává, a další pro uložení existujících úkolů. Pro účely tohoto kurzu se úlohy ukládají v paměti a ne trvalé úložiště.

  2. Přidejte následující příkaz importu pro TodoList.jsx pro import useState.

    import { useState } from 'react'
    
  3. Dále pomocí tohoto háku vytvořte stavové proměnné. Do funkce TodoList nad příkaz return přidejte následující kód.

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

    Tím se nastaví dvě proměnné, tasks a newTaskText, pro data a dvě funkce, které můžete volat k aktualizaci těchto proměnných, setTasks a setNewTasks. Když se změní hodnota stavu proměnné, React automaticky znovu vykreslí komponentu.

    Téměř jste připraveni aktualizovat TodoList.jsx, abyste zobrazili to-do položky jako seznam, ale nejprve je důležité pochopit důležitý koncept Reactu.

    Když v Reactu zobrazíte seznam položek, musíte přidat klíč, který jedinečně identifikuje jednotlivé položky v seznamu. Tato funkce je podrobně vysvětlená v dokumentaci Reactu v vykreslovacích seznamech, ale tady se seznámíte se základy. Máte seznam to-do položek, které se mají zobrazit, a potřebujete pro každou položku přidružit jedinečný klíč. Klíč pro každou položku by se neměl měnit a z tohoto důvodu nemůžete jako klíč použít index položky v poli. Potřebujete ID, které se po celou dobu životnosti těchto hodnot nezmění. K vytvoření jedinečného ID pro každou položku to-do použijete randomUUID().

  4. Vytvořte TodoList.jsx pomocí UUID jako klíče pro každou položku to-do. Aktualizujte todoList.jsx následujícím kódem.

    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;
    

    Vzhledem k tomu, že jsou hodnoty ID přiřazeny mimo funkci TodoList, můžete mít jistotu, že se hodnoty při opětovném vykreslení stránky nezmění. Když aplikaci vyzkoušíte v tomto stavu, všimnete si, že do vstupního elementu todo nemůžete zadávat. Důvodem je to, že vstupní prvek je vázán na newTaskText, který byl inicializován na prázdný řetězec. Pokud chcete uživatelům povolit přidávání nových úkolů, musíte na daném ovládacím prvku zpracovat onChange událost. Musíte také implementovat podporu tlačítka Přidat.

  5. Přidejte požadované funkce bezprostředně před příkaz return ve funkci 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();
    }
    

    Ve funkci handleInputChanged se nová hodnota ze vstupního pole předává prostřednictvím event.target.valuea tato hodnota slouží k aktualizaci hodnoty proměnné newTaskText pomocí setNewTaskText. Ve funkci addTask přidejte nový úkol do seznamu existujících úkolů pomocí setTasks a nastavte ID položky jako novou hodnotu UUID. Aktualizujte vstupní prvek tak, aby zahrnoval onChange={handleInputChange} a aktualizujte tlačítko Přidat tak, aby zahrnovalo onClick={addTask}. Tento kód propojí událost s funkcí, která ji zpracovává. Za tímto účelem byste měli být schopni do seznamu úkolů přidat nový úkol. Nové úkoly se přidají do dolní části seznamu. Aby byla tato aplikace užitečnější, musíte přidat podporu pro odstranění úkolů a přesunout úkol nahoru nebo dolů.

  6. Přidejte funkce pro podporu odstranění, přesunutí nahoru a přesunutí dolů, a pak aktualizujte označení tak, aby zobrazovalo tlačítko pro každou akci. Do funkce TodoList nad příkaz return přidejte následující kód.

    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);
        }
    }
    

    Funkce delete převezme ID úlohy a odstraní ji ze seznamu a pomocí metody Array filter() vytvoří nové pole s výjimkou vybrané položky a potom zavolá setTasks(). Ostatní dvě funkce přebírají index položky, protože tato práce je specifická pro řazení položek. moveTaskUp() i moveTaskDown() používají destrukturalizaci přiřazení pole pro prohození vybraného úkolu se sousedem.

  7. V dalším kroku aktualizujte zobrazení tak, aby zahrnovalo tyto tři tlačítka. Aktualizujte návratový příkaz tak, aby obsahoval následující.

    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>
    );
    

    Přidali jste tlačítka potřebná k provedení dříve probíraných úloh. Znaky Unicode používáte jako ikony na tlačítkách. V kódu jsou přidány některé atributy pro podporu pozdějšího přidání některých šablon stylů CSS. Můžete si také všimnout použití atributů aria ke zlepšení přístupnosti, které jsou volitelné, ale důrazně doporučujeme. Pokud aplikaci spustíte, měla by vypadat jako na následujícím obrázku.

    snímek obrazovky zobrazující spuštěnou aplikaci a seznam

    Teď byste měli být schopni ve webové aplikaci TODO provést následující.

    • Přidat úkol
    • Odstranit úkol
    • Přesunout úkol nahoru
    • Přesunout úkol dolů

    Tyto funkce fungují, ale můžete refaktorovat k vytvoření opakovaně použitelné komponenty pro zobrazení to-do položek. Kód položky to-do přejde do nové komponenty TodoItem. Jelikož správa seznamu zůstává v komponentě Todo, můžete k tlačítkům Odstranit a Přesunout předat funkce zpětného volání.

  8. Začněte tak, že v Průzkumníku řešení kliknete pravým tlačítkem na složku komponent a vyberete Přidat > Nová položka.

  9. V dialogovém okně, které se otevře, vyberte React JSX Component File, pojmenujte ho TodoItem a vyberte Přidat.

  10. Do todoItem přidejte následující kód.

    V tomto kódu předáte úlohu a zpětná volání jako vlastnosti této nové součásti.

    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;
    

    Předchozí kód obsahuje kód ze komponenty Todo a na konci deklarujete PropTypes. Props se používají k předávání dat z nadřazené komponenty do podřízených komponent. Další informace o props naleznete v tématu Předávání props komponentě – React. Vzhledem k tomu, že funkce delete a move se předávají jako zpětná volání, musí být obslužná rutina onClick aktualizována, aby mohla tyto zpětná volání vyvolat.

  11. Přidejte požadovaný kód. Zde je uveden úplný kód pro TodoList, který používá komponentu TodoItem.

    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;
    

    Nyní se komponenta TodoItem používá k vykreslení každé to-do položky. Všimněte si, že klíč je nastavený na task.id, který obsahuje hodnotu UUID pro daný úkol. Při spuštění aplikace byste neměli vidět žádné změny vzhledu nebo chování aplikace, protože jste ji refaktorovali tak, aby používala TodoItem.

    Teď, když máte všechny základní funkce podporované, je čas začít do toho přidávat nějaký styl, aby vypadal hezky. Začněte přidáním odkazu v Index.html pro rodinu písem Inter, kterou použijete pro tuto aplikaci. V Index.htmljsou některé další položky, které je potřeba vyčistit. Konkrétně by se měl název aktualizovat a chcete nahradit vite.svg soubor, který se aktuálně používá jako ikona.

  12. Aktualizujte Index.html následujícím obsahem.

    <!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. Upravte soubor main.jsx tak, aby při volání rootnahradil maincreateRoot .

    Tady je uvedený úplný kód pro main.jsx.

    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>,
    )
    

    Kromě těchto změn se soubor checkmark-square.svg přidal do veřejné složky. Toto je SVG obrázek značky zaškrtnutí ve tvaru čtverce z FluentUI, který si můžete stáhnout přímo. (Existuje balíček, který můžete použít pro integrovanější prostředí, ale to je mimo rozsah tohoto článku.)

    Dále aktualizujte styly komponenty TodoList.

  14. Do složky komponent přidejte nový soubor CSS s názvem TodoList.css. Můžete kliknout pravým tlačítkem myši na projekt a vybrat Přidat > Nová položka a pak vybrat šablonu stylů. Zadejte název souboru TodoList.css.

  15. Do TodoList.csspřidejte následující kód.

    .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. Dále upravte TodoList.jsx a přidejte do horní části souboru následující import.

    import './TodoList.css';
    
  17. Po uložení změn aktualizujte prohlížeč. Tím by se měl zlepšit styl aplikace. Aplikace by měla vypadat nějak takto.

    Snímek obrazovky zobrazující konečnou verzi spuštěné aplikace

    Teď jste vytvořili funkční aplikaci seznamu to-do, která ukládá položky to-do do paměti. Od tohoto okamžiku byste mohli aplikaci aktualizovat tak, aby ukládaly to-do položky v localStorage/IndexedDb, nebo ji integrovala s databází na straně serveru nebo s jiným back-endem pro trvalejší úložiště.

Shrnutí

V tomto kurzu jste pomocí sady Visual Studio vytvořili novou aplikaci React. Aplikace se skládá ze seznamu to-do, který zahrnuje podporu pro přidávání úkolů, odstraňování úkolů a jejich uspořádání. Vytvořili jste dvě nové komponenty React a použili jste je v tomto kurzu.

Prostředky