npx create-react-app react-twilio-sms cd react-twilio-sms npm start
npm start
, will start the development server. In your browser, head over to http://localhost:3000. You will see the following:create-react-app
.import './index.css';
from the top of src/index.js.import React from 'react'; function App() { return ( <div className="App"> </div> ); } export default App;
npm install twilio react-bootstrap bootstrap
import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import 'bootstrap/dist/css/bootstrap.min.css';
react-bootstrap
to create a form that receives a phone number and message from the user.Container
component from the react-bootstrap
library in App.js and then add a Container
to the form.import React from "react"; import { Container } from "react-bootstrap"; function App() { return ( <div className="App"> <Container> </Container> </div> ); } export default App;
Container
component has added margins on both sides. This will be more apparent after adding a heading using the <h2>
tag.return ( <div className="App"> <Container> <h2>Send SMS</h2> </Container> </div> );
Form
component. You can read more about Form
in the documentation.Container
import to include Form
at the top of App.js like this:import { Container, Form } from "react-bootstrap";
Form
component to the Container
component. Your form needs two fields: one text field for the number where the message is to be sent, and one textarea field for the message itself. Label these fields To
and Body
, respectively. See the following form code:<Container> <h2>Send SMS</h2> <Form> <Form.Group> <Form.Label htmlFor="to">To</Form.Label> <Form.Control /> </Form.Group> <Form.Group> <Form.Label htmlFor="message">Body</Form.Label> <Form.Control as="textarea" rows="3" /> </Form.Group> </Form> </Container>
Button
component from react-bootstrap
and add it to the form.import React from "react"; import { Container, Form, Button } from "react-bootstrap"; function App() { return ( <div className="App"> <Container> <h2>Send SMS</h2> <Form> <Form.Group> <Form.Label htmlFor="to">To</Form.Label> <Form.Control /> </Form.Group> <Form.Group> <Form.Label htmlFor="message">Body</Form.Label> <Form.Control as="textarea" rows="3" /> </Form.Group> <Button variant="primary" type="submit"> Send </Button> </Form> </Container> </div> ); } export default App;
useState()
hook.import React, {useState} from "react";
App
component, define two states: number
and body
. As their names suggest, number
will store the phone number and body
will store the body of the SMS message.function App() { const [number, setNumber] = useState(""); const [body, setBody] = useState(""); ... }
To
field:<Form.Group> <Form.Label htmlFor="to">To</Form.Label> <Form.Control value={number} onChange={(e) => setNumber(e.target.value)} /> </Form.Group>
value
and onChange
tags to the form control creates a two-way data bind, which means that if the field is updated on the UI side, then the number
state will get updated accordingly and vice versa.body
field. Edit your code to reflect the following:<Form.Group> <Form.Label htmlFor="message">Body</Form.Label> <Form.Control as="textarea" rows="3" value={body} onChange={(e) => setBody(e.target.value)} /> </Form.Group>
<Container>
component.return ( <div className="App"> <Container> ... </Container> {console.log(`Number is ${number} and the Message is ${body}`)} </div> );
CTRL + Shift + J
in Chrome or CTRL + Shift + K
in Firefox. Now try typing in the To
and Body
fields; you will see the same data in the console in real-time.console.log()
line from App.js.ACCOUNT_SID
, AUTH_TOKEN
, and your Twilio phone number. If you are on a trial subscription, you will need to get a trial phone number.create-react-app
you won't need to install the dotenv
package separately. Be sure to prefix all environment variables with REACT_APP_
. Read more about this here.touch .env
REACT_APP_TWILIO_ACCOUNT_SID=your_account_sid REACT_APP_TWILIO_AUTH_TOKEN=your_auth_token REACT_APP_TWILIO_PHONE_NUMBER= your_twilio_number
vercel
CLI on your local machine by running the following command:npm install --global vercel
vercel
vercel
command a second time. There will be several prompts to answer, hit enter
to move through them with pre-populated responses or answer them accordingly.Vercel CLI 20.1.0 ? Set up and deploy "D:\Blog\Twilio\1\react-twilio-sms"? [Y/n] y ? Which scope do you want to deploy to? Ashutosh K Singh ? Link to existing project? [y/N] n ? What's your project's name? react-twilio-sms ? In which directory is your code located? ./ Auto-detected Project Settings (Create React App): - Build Command: `npm run build` or `react-scripts build` - Output Directory: build - Development Command: react-scripts start ? Want to override the settings? [y/N] n � Linked to lelouch-b/react-twilio-sms (created .vercel and added it to .gitignore) � Inspect: https://vercel.com/lelouch-b/react-twilio-sms/g4rke71lh [1s] ✅ Production: https://react-twilio-sms.vercel.app [copied to clipboard] [50s] � Deployed to production. Run `vercel --prod` to overwrite later (https://vercel.link/2F). � To change the domain or build command, go to https://vercel.com/lelouch-b/react-twilio-sms/settings
vercel dev
npm start
, but the difference is that this time you can create and test serverless functions with Vercel.mkdir api
touch api/helloWorld.js
req
and res
, which can be used to access request parameters, set headers, send information, etc.export default (req, res) => { res.statusCode = 200; res.send({ message: "helloWorld" }); };
{"message":"helloWorld"}
touch api/sendMessage.js
export default async (req, res) => { res.statusCode = 200; res.setHeader("Content-Type", "application/json"); }
process.env
.const client = require("twilio")( process.env.REACT_APP_TWILIO_ACCOUNT_SID, process.env.REACT_APP_TWILIO_AUTH_TOKEN ); export default async (req, res) => { res.statusCode = 200; res.setHeader("Content-Type", "application/json"); }
messages.create()
method, where from
is your Twilio number that is stored inside .env.to
and body
are set by the user on the client side when they submit the form. These are accessed using req.body.to
and req.body.body
.export default async (req, res) => { res.statusCode = 200; res.setHeader("Content-Type", "application/json"); client.messages.create({ from: process.env.REACT_APP_TWILIO_PHONE_NUMBER, to: req.body.to, body: req.body.body, }) .then(() => { res.send(JSON.stringify({ success: true })); }) .catch((err) => { console.log(err); res.send(JSON.stringify({ success: false })); }); };
onSubmit
event listener to the Form
component. The onSubmit
event will trigger the onSubmit
function when the user submits the form. This onSubmit
function will be written in the next step.<Form onSubmit={onSubmit}> ... </Form>
onSubmit
function. This function will be responsible for sending the SMS message to the number submitted through the form. Inside this function, you will use the fetch
API to POST
to your serverless function.function App() { const [number, setNumber] = useState(""); const [body, setBody] = useState(""); const onSubmit = async (e) => { await e.preventDefault(); const res = await fetch("/api/sendMessage", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ to: number, body: body }), }); const data = await res.json(); if (data.success) { await setNumber(""); await setBody(""); } else { await setNumber("An Error has occurred."); await setBody("An Error has occurred."); } }; }
const onSubmit = async (e) => { ... }
e.preventDefault()
is used to prevent the page from refreshing or reloading.const onSubmit = async (e) => { await e.preventDefault(); ... }
fetch
API is used to post the number and message to the sendMessage
endpoint. In the POST
request body, a JSON object containing the to
and body
values are converted to a string using JSON.stringify()
.const onSubmit = async (e) => { await e.preventDefault(); const res = await fetch("/api/sendMessage", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ to: number, body: body }), }); }
data
variable. Based on whether the value of data.success
is true or false, the fields are either cleared or a message “An Error has occurred” is shown to the user.const onSubmit = async (e) => { await e.preventDefault(); const res = await fetch("/api/sendMessage", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ to: number, body: body }), }); const data = await res.json(); if (data.success) { await setNumber(""); await setBody(""); } else { await setNumber("An Error has occurred."); await setBody("An Error has occurred."); } };
vercel dev
. Head over to http://localhost:3000 and try sending a message. Note: If you are on a trial subscription you can only send an SMS message to verified numbers.