Dela via


Skapa en React-app i Visual Studio

I den här handledningen skapar du en React-front-end för en to-do-lista med hjälp av JavaScript och Visual Studio 2022. Koden för den här appen finns på ToDoJSWebApp.

Förutsättningar

Se till att installera följande:

Skapa React ToDo List-appen

  1. I Visual Studio väljer du File > New > Project för att öppna dialogrutan Skapa ett nytt projekt, välj mallen React App JavaScript och välj sedan Nästa.

    Skärmbild som visar hur du väljer en mall.

  2. Ge projektet namnet TodoWebApp och välj Skapa.

    Då skapas JavaScript-projektet med kommandoradsverktyget vite.

  3. Högerklicka på mappen src i Solution Explorer och välj Lägg till > ny mapp. och skapa en ny mapp med namnet components.

    Det är en vanlig konvention att placera komponenter i en komponentmapp, men det krävs inte.

  4. Högerklicka på den nya mappen, välj Lägg till > React JSX-komponentfil, ge den namnet TodoListoch klicka på Lägg till.

    Skärmbild som visar hur du lägger till en JSX-komponent.

    Då skapas en ny JSX-fil i komponentmappen.

  5. Öppna komponenten TodoList och ersätt standardinnehållet med följande:

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

    Den här komponenten visar en rubrik som du kommer att ersätta senare.

    Anslut sedan den här komponenten i appen. App.jsx är huvudkomponenten som läses in, som representerar to-do listapplikationen. Den här komponenten används i filen main.jsx.

  6. I Solution Explorer öppnar du App.jsx, tar bort alla importer överst och rensar ut innehållet i returutdraget. Filen bör se ut så här.

    function App() {
      return (
        <>
          <TodoList />
        </>
      );
    }
    export default App;
    
  7. Om du vill lägga till TodoList-komponenten placerar du markören i fragmentet och skriver sedan <TodoL RETURN. Detta lägger till komponenten och import-instruktionen.

    Skärmbild som visar hur du lägger till en JSX-komponent i appen.

    Rensa sedan CSS-filerna.

  8. Öppna App.css och ta bort allt innehåll.

  9. Öppna Index.css och ta bort allt innehåll förutom formatmallarna för :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;
    }
    

Kör appen

Välj knappen Starta felsökning i verktygsfältet eller tryck på kortkommandot F5.

Appen öppnas i ett webbläsarfönster.

Skärmbild som visar appen som körs i webbläsaren.

Lägg till to-do listfunktioner i appen

Du kan låta appen köras. När du gör ändringar uppdateras appen automatiskt med det senaste innehållet med hjälp av Vites stöd för ersättning av frekventa moduler. Vissa åtgärder, till exempel att lägga till mappar eller byta namn på filer, kräver att du slutar felsöka och sedan startar om appen, men i allmänhet kan du låta den köras i bakgrunden när du utvecklar appen. Öppna komponenten TodoList.jsx så att vi kan börja definiera den.

  1. I Solution Explorer öppnar du TodoList.jsx och lägger till det användargränssnitt som behövs för att visa och hantera to-do listposter. Ersätt innehållet med följande kod:

    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;
    

    Föregående kod lägger till en indataruta för den nya to-do uppgiften och en knapp för att skicka indata. Sedan kopplar du upp knappen Lägg till. Använd useState React-kroken för att lägga till två tillståndsvariabler, en för uppgiften som läggs till och en annan för att lagra befintliga uppgifter. I den här handledningen lagras uppgifterna i minnet och inte i permanent lagring.

  2. Lägg till följande importuttryck i TodoList.jsx för att importera useState.

    import { useState } from 'react'
    
  3. Använd sedan den kroken för att skapa tillståndsvariablerna. Lägg till följande kodsnutt i TodoList-funktionen ovanför retursatsen.

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

    Detta konfigurerar två variabler, tasks och newTaskText, för data och två funktioner som du kan anropa för att uppdatera variablerna, setTasks och setNewTasks. När ett värde för en tillståndsvariabel ändras återger React komponenten automatiskt igen.

    Du är nästan redo att uppdatera TodoList.jsx för att visa to-do objekt som en lista, men det finns ett viktigt React-koncept att lära dig först.

    När du visar en lista med objekt i React måste du lägga till en nyckel för att unikt identifiera varje objekt i listan. Den här funktionen beskrivs ingående i React-dokumenten på Renderingslistor, men här lär du dig grunderna. Du har en lista över to-do objekt som ska visas och du måste associera en unik nyckel för varje objekt. Nyckeln för varje objekt bör inte ändras och därför kan du inte använda objektets index i matrisen som nyckel. Du behöver ett ID som inte ändras under dessa värdens livslängd. Du använder randomUUID() för att skapa ett unikt ID för varje to-do objekt.

  4. Skapa TodoList.jsx med en UUID som nyckel för varje to-do objekt. Uppdatera TodoList.jsx- med följande kod.

    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;
    

    Eftersom ID-värdena tilldelas utanför funktionen TodoList kan du vara säker på att värdena inte ändras om sidan återges på nytt. När du provar appen i det här tillståndet ser du att du inte kan skriva in i todo-indataelementet. Det beror på att indataelementet är bundet till newTaskText, som har initierats till en tom sträng. Om du vill tillåta användare att lägga till nya uppgifter måste du hantera onChange-händelsen på den kontrollen. Du måste också implementera stöd för knappen Lägg till.

  5. Lägg till de nödvändiga funktionerna omedelbart före retursatsen i funktionen 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();
    }
    

    I funktionen handleInputChanged skickas det nya värdet från indatafältet via event.target.valueoch det värdet används för att uppdatera värdet för variabeln newTaskText med setNewTaskText. I funktionen addTask lägger du till den nya aktiviteten i listan över befintliga aktiviteter med hjälp av setTasks och anger objektets ID som ett nytt UUID-värde. Uppdatera indataelementet så att det innehåller onChange={handleInputChange} och uppdatera knappen Lägg till för att inkludera onClick={addTask}. Den här koden kopplar händelsen till den funktion som hanterar händelsen. Efter detta bör du kunna lägga till en ny uppgift i uppgiftslistan. Nya uppgifter läggs till längst ned i listan. För att göra den här appen mer användbar måste du lägga till stöd för att ta bort uppgifter och flytta en aktivitet uppåt eller nedåt.

  6. Lägg till funktionerna för att stödja borttagning, flytta upp och flytta nedåt och uppdatera sedan markering för att visa en knapp för varje åtgärd. Lägg till följande kod i funktionen TodoList ovanför retursatsen.

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

    Borttagningsfunktionen tar in aktivitets-ID:t och tar bort det från listan och använder metoden Array filter() för att skapa en ny matris exklusive det markerade objektet och anropar sedan setTasks(). De andra två funktionerna tar in objektets index eftersom det här arbetet är specifikt för objektordningen. Både moveTaskUp() och moveTaskDown() använder tilldelning med matrisdestrukturering för att växla den valda uppgiften med grannen.

  7. Uppdatera sedan vyn så att den innehåller de här tre knapparna. Uppdatera retursatsen så att den innehåller följande.

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

    Du har lagt till knapparna som behövs för att utföra de uppgifter som vi diskuterade tidigare. Du använder Unicode-tecken som ikoner på knapparna. I markupen finns det några attribut som har lagts till som stöd för att lägga till CSS-stilar senare. Du kanske också märker användningen av aria-attribut för att förbättra tillgängligheten, vilket är valfritt men rekommenderas starkt. Om du kör appen bör den se ut som följande bild.

    Skärmbild som visar appen som körs och visar en lista

    Du bör nu kunna utföra följande i TODO-webbappen.

    • Lägg till aktivitet
    • Ta bort uppgift
    • Flytta upp uppgiften
    • Flytta aktiviteten nedåt

    Dessa funktioner fungerar, men du kan omstrukturera för att skapa en återanvändbar komponent för att visa to-do objekt. Markup för objektet to-do placeras i den nya komponenten TodoItem. Eftersom hanteringen av listan finns kvar i Todo-komponenten kan du skicka återanrop till knapparna Ta bort och Flytta.

  8. Kom igång genom att högerklicka på mappen komponenter i Solution Explorer och välja Lägg till > nytt objekt.

  9. I dialogrutan som öppnas väljer du React JSX-komponentfilen, ger den namnet TodoItem och väljer Lägg till.

  10. Lägg till följande kod i TodoItem.

    I den här koden skickar du uppgiften och återanrop som egenskaper till den nya komponenten.

    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;
    

    Föregående kod innehåller markering från Todo-komponenten och i slutet av den deklarerar du PropTypes. Props används för att skicka data från en föräldrakomponent till barnkomponenter. Mer information om rekvisita finns i Skicka rekvisita till en komponent – React. Eftersom funktionerna för att ta bort och flytta skickas som återanrop måste onClick-hanteraren uppdateras för att anropa dessa återanrop.

  11. Lägg till den kod som krävs. Den fullständiga koden för TodoList som använder TodoItem-komponenten visas här.

    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;
    

    Nu används TodoItem-komponenten för att återge varje to-do objekt. Observera att nyckeln är inställd på task.id, som innehåller UUID-värdet för aktiviteten. När du kör appen bör du inte se några ändringar i appens utseende eller beteende eftersom du omstrukturerade den för att använda TodoItem.

    Nu när du har alla grundläggande funktioner som stöds är det dags att börja lägga till lite stil för att få det att se snyggt ut. Börja med att lägga till en länk i Index.html för en teckensnittsfamilj, Inter, som du ska använda för den här appen. I Index.htmlfinns det några andra objekt som måste rensas. Mer specifikt bör rubriken uppdateras och du vill ersätta den vite.svg fil som för närvarande används som ikon.

  12. Uppdatera Index.html med följande innehåll.

    <!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. Redigera main.jsx--fil för att ersätta root med main när du anropar createRoot.

    Den fullständiga koden för main.jsx- visas här.

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

    Förutom dessa ändringar lades filen checkmark-square.svg till i den gemensamma mappen. Det här är en SVG från fluentui-bockmarkeringens kvadratbild, som du kan ladda ned direkt. (Det finns ett paket som du kan använda för en mer integrerad upplevelse, men som inte omfattas av den här artikeln.)

    Uppdatera sedan formatmallarna för TodoList-komponenten.

  14. I komponentmappen lägger du till en ny CSS-fil med namnet TodoList.css. Du kan högerklicka på projektet och välja Lägg till > nytt objekt och sedan välja formatmall. Ge filen namnet TodoList.css.

  15. Lägg till följande kod i 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. Redigera sedan TodoList.jsx- för att lägga till följande import överst i filen.

    import './TodoList.css';
    
  17. Uppdatera webbläsaren när du har sparat ändringarna. Detta bör förbättra appens utseende. Appen bör se ut så här.

    Skärmbild som visar den slutliga versionen av appen som körs.

    Nu har du skapat en fungerande to-do listapp som lagrar de to-do objekten i minnet. Från och med nu kan du uppdatera appen för att lagra de to-do objekten i localStorage/IndexedDbeller integrera den med en databas på serversidan eller annan serverdel för mer permanent lagring.

Sammanfattning

I den här självstudien skapade du en ny React-app med Visual Studio. Appen består av en to-do lista, som innehåller stöd för att lägga till uppgifter, ta bort uppgifter och ordna om dem. Du har skapat två nya React-komponenter och använt dem i den här självstudien.

Resurser