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:
- Visual Studio 2022 eller senare. Gå till Visual Studio nedladdningar-sidan och installera den kostnadsfritt.
- npm (
https://www.npmjs.com/
), som ingår i Node.js.
Skapa React ToDo List-appen
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.
Ge projektet namnet
TodoWebApp
och välj Skapa.Då skapas JavaScript-projektet med kommandoradsverktyget vite.
Högerklicka på mappen
src
i Solution Explorer och välj Lägg till > ny mapp. och skapa en ny mapp med namnetcomponents
.Det är en vanlig konvention att placera komponenter i en komponentmapp, men det krävs inte.
Högerklicka på den nya mappen, välj Lägg till > React JSX-komponentfil, ge den namnet
TodoList
och klicka på Lägg till.Då skapas en ny JSX-fil i komponentmappen.
Ö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 filenmain.jsx
.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;
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.Rensa sedan CSS-filerna.
Öppna
App.css
och ta bort allt innehåll.Ö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.
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.
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.
Lägg till följande importuttryck i
TodoList.jsx
för att importerauseState
.import { useState } from 'react'
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
ochnewTaskText
, för data och två funktioner som du kan anropa för att uppdatera variablerna,setTasks
ochsetNewTasks
. 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.
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 hanteraonChange
-händelsen på den kontrollen. Du måste också implementera stöd för knappen Lägg till.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 viaevent.target.value
och det värdet används för att uppdatera värdet för variabelnnewTaskText
medsetNewTaskText
. I funktionenaddTask
lägger du till den nya aktiviteten i listan över befintliga aktiviteter med hjälp avsetTasks
och anger objektets ID som ett nytt UUID-värde. Uppdatera indataelementet så att det innehålleronChange={handleInputChange}
och uppdatera knappen Lägg till för att inkluderaonClick={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.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ådemoveTaskUp()
ochmoveTaskDown()
använder tilldelning med matrisdestrukturering för att växla den valda uppgiften med grannen.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.
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.
Kom igång genom att högerklicka på mappen komponenter i Solution Explorer och välja Lägg till > nytt objekt.
I dialogrutan som öppnas väljer du React JSX-komponentfilen, ger den namnet TodoItem och väljer Lägg till.
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åsteonClick
-hanteraren uppdateras för att anropa dessa återanrop.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.
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>
Redigera main.jsx--fil för att ersätta
root
medmain
när du anroparcreateRoot
.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.
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.
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; }
Redigera sedan TodoList.jsx- för att lägga till följande import överst i filen.
import './TodoList.css';
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.
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
- Kod för det här exemplet på ToDoJSWebApp
- Visual Studio JavaScript- och TypeScript-projekt