## 3: Forms and Events All apps need to allow the user to perform some sort of interaction with the data that is stored. In our case, the first type of interaction is to insert new tasks. Without it, our To-Do app wouldn't be very helpful. One of the main ways in which a user can insert or edit data on a website is through forms. In most cases, it is a good idea to use the `
` tag since it gives semantic meaning to the elements inside it. ### 3.1: Create Task Form First, we need to create a simple form component to encapsulate our logic. As you can see we set up the `useState` React Hook. Please note the _array destructuring_ `[text, setText]`, where `text` is the stored value which we want to use, which in this case will be a _string_; and `setText` is a _function_ used to update that value. Create a new file `TaskForm.jsx` in your `ui` folder. ::: code-group ```js [imports/ui/TaskForm.jsx] import React, { useState } from "react"; export const TaskForm = () => { const [text, setText] = useState(""); return (
); }; ``` ::: ### 3.2: Update the App component Then we can simply add this to our `App` component above your list of tasks: ::: code-group ```js [imports/ui/App.jsx] import React from "react"; import { useTracker, useSubscribe } from "meteor/react-meteor-data"; import { TasksCollection } from "/imports/api/TasksCollection"; import { Task } from "./Task"; import { TaskForm } from "./TaskForm"; export const App = () => { const isLoading = useSubscribe("tasks"); const tasks = useTracker(() => TasksCollection.find({}).fetch()); if (isLoading()) { return
Loading...
; } return (

Welcome to Meteor!

); }; ``` ::: ### 3.3: Update the Stylesheet You also can style it as you wish. For now, we only need some margin at the top so the form doesn't seem off the mark. Add the CSS class `.task-form`, this needs to be the same name in your `className` attribute in the form component. ::: code-group ```css [client/main.css] .task-form { margin-top: 1rem; } ``` ::: ### 3.4: Add Submit Handler Now let's create a function to handle the form submit and insert a new task into the database. To do it, we will need to implement a Meteor Method. Methods are essentially RPC calls to the server that let you perform operations on the server side securely. You can read more about Meteor Methods [here](https://guide.meteor.com/methods.html). To create your methods, you can create a file called `tasksMethods.js`. ::: code-group ```javascript [imports/api/tasksMethods.js] import { Meteor } from "meteor/meteor"; import { TasksCollection } from "./TasksCollection"; Meteor.methods({ "tasks.insert"(doc) { return TasksCollection.insertAsync(doc); }, }); ``` ::: Remember to import your method on the `main.js` server file and the `main.jsx` client file. ::: code-group ```javascript [server/main.js] import { Meteor } from "meteor/meteor"; import { TasksCollection } from "../imports/api/tasksCollection"; import "../imports/api/TasksPublications"; import "../imports/api/tasksMethods"; // [!code highlight] ``` ```javascript [client/main.jsx] import React from "react"; import { createRoot } from "react-dom/client"; import { Meteor } from "meteor/meteor"; import { App } from "/imports/ui/App"; import "../imports/api/tasksMethods"; // [!code highlight] ``` ::: Now you can attach a submit handler to your form using the `onSubmit` event, and also plug your React Hook into the `onChange` event present in the input element. As you can see you are using the `useState` React Hook to store the `value` of your `` element. Note that you also need to set your `value` attribute to the `text` constant as well, this will allow the `input` element to stay in sync with our hook. > In more complex applications you might want to implement some `debounce` or `throttle` logic if there are many calculations happening between potentially frequent events like `onChange`. There are libraries which will help you with this, like [Lodash](https://lodash.com/), for instance. ::: code-group ```js [imports/ui/TaskForm.jsx] import React, { useState } from "react"; import { TasksCollection } from "/imports/api/TasksCollection"; export const TaskForm = () => { const [text, setText] = useState(""); const handleSubmit = async (e) => { e.preventDefault(); if (!text) return; await Meteor.callAsync("tasks.insert", { text: text.trim(), createdAt: new Date(), }); setText(""); }; return (
setText(e.target.value)} />
); }; ``` ::: Inside the function, we are adding a task to the `tasks` collection by calling `Meteor.callAsync()`. The first argument is the name of the method we want to call, and the second argument is the text of the task. We are also trimming the text to remove any extra spaces. Also, insert a date `createdAt` in your `task` document so you know when each task was created. ### 3.5: Show Newest Tasks First Now you just need to make a change that will make users happy: we need to show the newest tasks first. We can accomplish this quite quickly by sorting our [Mongo](https://guide.meteor.com/collections.html#mongo-collections) query. ::: code-group ```js [imports/ui/App.jsx] .. export const App = () => { const tasks = useTracker(() => TasksCollection.find({}, { sort: { createdAt: -1 } }).fetch()); .. ``` ::: Your app should look like this: In the next step, we are going to update your tasks state and provide a way for users to remove tasks.