React Quick Reference
What React is
From the official docs:
React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
- React is a JavaScript library for building user interfaces. Some people use it as the V in MVC -- Model-View-Controller paradigm
- In React, we solve problems by creating components. If a component gets too complex, we break it into smaller, simpler components.
Main concepts
- Components: a component in React works similarly to JavaScript functions: It generates an output every time it is invoked.
- Virtual DOM: The virtual DOM is an in-memory representation of real DOM elements generated by React components before any changes are made to the page.
- Virtual DOM diffing: Virtual DOM diffing allows React to minimize changes to the DOM as a result of user actions therefore, increasing browser performance. -- only the changes to the DOM are rendered
How React processes a component
Given this example JSX code:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
It would be translated into a React.CreateElement()
call:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
And then into a "React Element", which is ultimately a JavaScript object:
// Note: this structure is simplified
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world'
}
};
From the official docs:
Elements are the smallest building blocks of React apps. Unlike browser DOM elements, React elements are plain objects, and are cheap to create. React DOM takes care of updating the DOM to match the React elements.
One might confuse elements with a more widely known concept of “components”; elements are what components are “made of” […]
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.
While components commonly use the JS class
syntax, they also exist in a simpler form as "functional components":
function MyComp(props) {
return (
<h1>Hello, {props.name}</h1>
);
}
Functional components are stateless, that is, they don't support state.
Anatomy of a React component
- Components in React are JavaScript classes that inherit from the
React.Component
base class. - Components:
- Implement a
render()
method that takes input data and returns what to display - Manage input data via
this.props
- Manage internal state data via
this.state
(stateful components)
- Implement a
JS class refresher
- JavaScript classes are an ES6 enhancement over constructor functions
- The class syntax is not introducing a new object model to JavaScript. It’s just syntactical sugar over the existing prototype-based inheritance.
- We can use class inheritance to reduce code repetition. Child classes inherit and specialize behavior defined in parent classes.
Example
// defining a class
class MyClass {
// runs every time a new instance is created w/ new
constructor(data, moreData) {
this.data = data;
this.moreData = moreData;
}
myMethod() {
//
}
}
// creating an instance
var classInstance = new MyClass('lorem', 'ipsum');
classInstance.myMethod();
The extends
keyword is used to create a class that inherits methods and properties from another class. The super()
method calls the parent class' constructor.
The
super
keyword is used to call functions on an object's parent. When used in a constructor, thesuper
keyword appears alone and must be used before thethis
keyword can be used. This keyword can also be used to call functions on a parent object.
class Descendant extends MyClass {
constructor(data, moreData) {
// we run the parent's constructor
super();
//
}
}
Creating a React component
We create a React component by defining a new class that extends
the React.Component
base class:
class MyComponent extends React.Component {
render() {
return ( <JSX code, no quotes> );
}
}
ReactDOM.render(<MyComponent />, <DOM target>);
Breakdown:
render()
this is a required method that we'll use to return JSX (JavaScript XML) codereturn ( <JSX code, no quotes> );
we return the code as JSX w/o quotes (not a string)- JSX will be transpiled to JavaScript, and ultimately rendered to the DOM as HTML
ReactDOM.render(component, target);
reads the output from ourrender()
method and renders our component to the DOM<MyComponent />
we pass in our component as a self-closing HTML tag named after our component
JavaScript in JSX
JSX can contain portions of JavaScript, as long as they're enclosed in curly braces -- they will be interpreted as literal JavaScript.
class MyComponent extends React.Component {
render() {
let today = new Date();
return (
<div className='todayInfo'>
<p>Today is: {today.toDateString()}</p>
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.getElementById('myTarget'));
Notice that, since class
is a reserved keyword in JS, the HTML class attribute becomes className
.
Another example of plain JS in JSX, in which we generate and populate a series of <li>
s by iterating over an array:
class MyComponent extends React.Component {
render() {
let randWords = [
'Lorem',
'Ipsum',
'Dolor'
];
return (
<div>
<p>Here are some random words:</p>
<ul>
{randWords.map( (el) => { <li>{el}</li> } )}
</ul>
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.getElementById('myTarget'));
ES6 String templates
String templates have a special syntax -- ${<var>} <string>
all enclosed in backticks -- and JSX can recognize it as long as it's inside curly braces:
<img src={this.props.avatarUrl} alt={`${this.props.author}'s picture`} />
Passing data with props
Let's assume we have a webpage with a comment-box
container that holds a series of comment
components:
.comment-box
.comment
.comment
.comment
In order to render the page elements with React, we'll create two components: CommentBox
and Comment
.
Since we want the data in the Comment
component to be dynamic, we'll define a series of props; the props will receive arguments from the CommentBox
component.
We define props with the syntax {this.props.<propname>}
. Notice we're just creating a reference (like a parameter), we don't need to provide any value.
class Comment extends React.Component {
render() {
return(
<div className="comment">
<p className="comment-header">
{this.props.author}
</p>
<p className="comment-body">
{this.props.body}
</p>
<div className="comment-actions">
<a href="#">Delete comment</a>
</div>
</div>
);
}
}
Then, in our CommentBox
component we'll include our Comment
comps by just calling <Comment />
.
Lastly, to pass arguments we'll simply use the HTML attribute syntax:
class CommentBox extends React.Component {
render() {
return(
<div className="comment-box">
<h3>Comments</h3>
<h4 className="comment-count">2 comments</h4>
<div className="comment-list">
<Comment author='Anne Droid' body='I want to know what love is...' />
</div>
</div>
);
}
}
class Comment extends React.Component
Dynamic props
We learned how to pass arguments to our components, but they're just hardcoded values: what if we wanted to pass dynamic arguments?
Since JSX processes JavaScript, we can use iteration methods such as .map()
to dynamically populate our props.
Here's an example:
class CommentBox extends React.Component {
render() {
const comments = this._getComments() || [];
return (
<div className="comment-box">
<h3>Comments</h3>
{this._getPopularMessage(comments.lenght)}
<h4 className="comment-count">{this._getCommentsTitle(comments.length)}</h4>
<div className="comment-list">
{comments}
</div>
</div>
);
}
_getPopularMessage(commentCount) {
const POPULAR_COUNT = 10;
if (commentCount > POPULAR_COUNT) {
return (
<div>This post is getting really popular, don't miss out!</div>
)
}
}
_getComments() {
const commentList = [
{ id: 1, author: 'Clu', body: 'Just say no to love!', avatarUrl: 'images/default-avatar.png' },
{ id: 2, author: 'Anne Droid', body: 'I wanna know what love is...', avatarUrl: 'images/default-avatar.png' }
];
return commentList.map((comment) => {
return (<Comment
author={comment.author}
body={comment.body}
avatarUrl={comment.avatarUrl}
key={comment.id} />);
});
}
_getCommentsTitle(commentCount) {
if (commentCount === 0) {
return 'No comments yet';
} else if (commentCount === 1) {
return '1 comment';
} else {
return `${commentCount} comments`;
}
}
}
class Comment extends React.Component {
render() {
return (
<div className="comment">
<img src={this.props.avatarUrl} alt={`${this.props.author}'s picture`} />
<p className="comment-header">{this.props.author}</p>
<p className="comment-body">
{this.props.body}
</p>
<div className="comment-actions">
<a href="#">Delete comment</a>
</div>
</div>
);
}
}
The breakdown:
We define our Comment
component, with the props we want to populate:
class Comment extends React.Component {
render() {
return (
<div className="comment">
<img src={this.props.avatarUrl} alt={`${this.props.author}'s picture`} />
<p className="comment-header">{this.props.author}</p>
<p className="comment-body">
{this.props.body}
</p>
<div className="comment-actions">
<a href="#">Delete comment</a>
</div>
</div>
);
}
}
Then, in CommentBox
, we create a _getComments()
method. This method will:
- Iterate over a provided data source (in this case it's static data in a
const
, but the typical case would be a JSON obj sent by a server) - Generate a call for a
<Comment />
component, and set the appropriate props with the values in our data source - Return an array with the resulting pre-populated component calls
- This array will then be handled by
CommentBox
, and the final result will be a series ofComment
components
- This array will then be handled by
Style note: it's a common practice to mark custom methods with a leading _
, in order to set them apart from React's built-in methods.
You can build collections of elements and include them in JSX using curly braces
{}
.
class CommentBox extends React.Component {
// (…)
_getComments() {
const commentList = [
{ id: 1, author: 'Clu', body: 'Just say no to love!', avatarUrl: 'images/default-avatar.png' },
{ id: 2, author: 'Anne Droid', body: 'I wanna know what love is...', avatarUrl: 'images/default-avatar.png' }
];
return commentList.map((comment) => {
return (<Comment
author={comment.author}
body={comment.body}
avatarUrl={comment.avatarUrl}
key={comment.id} />);
});
}
Now CommentBox
will render our dynamically populated Comment
components:
- In
const comments = this._getComments() || [];
we tell the component to call_getComments()
in order to receive our component array, and store it in a constant - In
{comments}
we populatecomment-list
with ourComment
comps
class CommentBox extends React.Component {
render() {
const comments = this._getComments() || [];
return (
<div className="comment-box">
<h3>Comments</h3>
{this._getPopularMessage(comments.lenght)}
<h4 className="comment-count">{this._getCommentsTitle(comments.length)}</h4>
<div className="comment-list">
{comments}
</div>
</div>
);
}
_getComments() { // }
// (…)
}
Also notice that, in {this._getPopularMessage(comments.lenght)}
and {this._getCommentsTitle(comments.length)}
we're reading into our generated array's length
in order to enable other functionalities:
_getPopularMessage(commentCount)
will generate a predefined message ifcomments.length
is > 10_getCommentsTitle(commentCount)
will handle singular/plural titles in ourh4.comment-count
class CommentBox extends React.Component {
render() {
//
}
_getPopularMessage(commentCount) {
const POPULAR_COUNT = 10;
if (commentCount > POPULAR_COUNT) {
return (
<div>This post is getting really popular, don't miss out!</div>
)
}
}
_getComments() {
//
}
_getCommentsTitle(commentCount) {
if (commentCount === 0) {
return 'No comments yet';
} else if (commentCount === 1) {
return '1 comment';
} else {
return `${commentCount} comments`;
}
}
}
Using Keys to uniquely identify elements
From the docs:
- Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
- The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys
- When you don’t have stable IDs for rendered items, you may use the item index as a key as a last resort (not recommended)
- Keys only make sense in the context of the surrounding array.
- A good rule of thumb is that elements inside the map() call need keys.
- Keys used within arrays should be unique among their siblings. However they don’t need to be globally unique. We can use the same keys when we produce two different arrays
Keys are an internal reference used by React and there's no need to expose them to the DOM -- in fact, it's considered an error. Only generate keys inside arrays/other iterable data structures.
State
React handles state by indirect DOM manipulation (as opposed to jQuery or plain JavaScript, which interact directly with the DOM API). To do this, it provides a state object that lives inside each component; we can access it by this.state
From the docs:
State is similar to props, but it is private and fully controlled by the component. […] state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it. […] Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree. This is commonly called a “top-down” or “unidirectional” data flow.
- State changes are usually triggered by user interactions with our app
- When writing a component in React that contains data that changes over time, it is considered a best practice to store this data in the component’s state.
- In order to create the initial state for a component, we must declare the property
this.state
as an object in the class constructor function. - Then, we don’t assign to the state object directly but instead we call
this.setState({<state-prop: value>})
by passing it an object. Calling setState will only update the properties passed as an argument, not replace the entire state object. - Calling
this.setState()
causes our component to re-render.
Let's implement state on our Comment
component:
class Comment extends React.Component {
constructor() {
super();
this.state = {
isAbusive: false
};
}
render() {
let commentBody;
if (!this.state.isAbusive) {
commentBody = this.props.body;
} else {
commentBody = <em>Content marked as abusive</em>;
}
return (
<div className="comment">
<img src={this.props.avatarUrl} alt={`${this.props.author}'s picture`} />
<p className="comment-header">{this.props.author}</p>
<p className="comment-body">
{commentBody}
</p>
<div className="comment-actions">
<a href="#">Delete comment</a>
<a href="#" onClick={this._toggleAbuse.bind(this)}>Report as Abuse</a>
</div>
</div>
);
}
_toggleAbuse(event) {
event.preventDefault();
this.setState({ isAbusive: !this.state.isAbusive })
}
}
The breakdown:
We create a constructor inside our component; the super()
method must be called first in order to call the parent class' constructor.
When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used. This keyword can also be used to call functions on a parent object.
We then proceed to create our state object with this.state
.
class Comment extends React.Component {
constructor() {
super();
this.state = {
isAbusive: false
};
}
//
}
Then we set up a conditional in order to tie our body
prop to a certain state.
Notice that in commentBody = <em>Content marked as abusive</em>;
we didn't use any brackets, nor quotes or backticks around our HTML element.
JSX can be returned into functions (no quotes)
class Comment extends React.Component {
render() {
// …
let commentBody;
if (!this.state.isAbusive) {
commentBody = this.props.body;
} else {
commentBody = <em>Content marked as abusive</em>;
}
return(
// …
<p className="comment-body">
{commentBody}
</p>
// …
);
}
// …
}
Finally, we create a _toggleAbuse(event)
method that toggles the true
/false
status of the isAbusive
property, and we call it from our UI via an onClick
attribute.
class Comment extends React.Component {
constructor() {
super();
this.state = {
isAbusive: false
};
}
render() {
// …
return(
// …
<div className="comment-actions">
<a href="#">Delete comment</a>
<a href="#" onClick={this._toggleAbuse.bind(this)}>Report as Abuse</a>
</div>
// …
);
}
_toggleAbuse(event) {
event.preventDefault();
this.setState({ isAbusive: !this.state.isAbusive })
}
}
- Notice the use of the bang
!
operator to set a value to its opposite - Notice the use of
bind()
inonClick={this._toggleAbuse.bind(this)}
The
bind()
method creates a new function that, when called, has itsthis
keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called. (The return value is) A copy of the given function with the specifiedthis
value and initial arguments. The simplest use ofbind()
is to make a function that, no matter how it is called, is called with a particularthis
value.
So in this case we're shifting the this
from the onClick
caller to our component.
Synthetic events
- We use React’s event system to capture user input, including form submissions and button clicks.
- Synthetic events are a cross-browser wrapper around the browser’s native event.
- React events are named in
camelCase
- React events are passed functions, not strings:
onClick:{myFunction}
-- notice the absence of()
, notonClick:"myFunction()"
- React events are named in
- When passing an event handler function, we need to
bind
the handler with.bind(this)
, i.e.<form className="comment-form" onSubmit={this._handleSubmit.bind(this)}>
- Common Synthetic events:
onClick
onChange
,onInput
,onSubmit
onKeyDown
,onKeyPress
,onKeyUp
onCopy
,onCut
,onPaste
When you define a component using an ES6
class
, a common pattern is for an event handler to be a method on the class.
Storing user input with refs
How do we pass user-submitted input to our event handler? We can use refs:
- Refs allow us to reference DOM elements in our code after the component has been rendered.
- With refs we can assign user input to properties in our component
- React runs ref callbacks on render
Example:
<div className="comment-form-fields">
<input placeholder="Name:" ref={c => this._author = c} />
<textarea placeholder="Comment:" ref={c => this._body = c} onChange={this._getCharacterCount.bind(this)}></textarea>
</div>
The syntax c => this._author = c
is the equivalent of:
function(c) {
this._author = c;
}
Notice how in this._author
we're creating an _author
property directly on this
.
From the docs:
While
this.props
is set up by React itself andthis.state
has a special meaning, you are free to add additional fields to the class manually if you need to store something that is not used for the visual output.
Constructor refresher
When declaring w/ this
in a constructor, we create object properties; classes work just like constructors in this respect.
function MyMovie(title, director, year) {
this.title = title;
this.director = director;
this.year = year;
}
let movie = new MyMovie('Movie', 'Director', 1999);
console.log(movie);
/* returns:
Object {
director: "Director",
title: "Movie",
year: 1999
}
*/
So, with our ref we are storing the user-submitted input c
into a newly-created _author
component property.
Passing values between components with callback props
How do we pass data from one component to the other?
- In React control flows from higher level components down to child components, forcing changes to happen reactively. This keeps apps modular and fast.
- Parent components can send data to child components using props.
- Child components can accept callback functions as props to communicate back with parent components.
- Parent components can pass callback functions as prop arguments to child components to allow two-way communication. In our example code:
CommentBox
CommentForm
Comment
The array of comments is part of CommentBox
(it resides in the component's state), so we need to propagate new comments from CommentForm
over to CommentBox
. In other words, new user-submitted comments must be added to CommentBox
's state. To do so we need to:
- In
CommentForm
, create anaddComment
prop like this one:this.props.addComment(this._author.value, this._body.value);
and add it to the event handler - In
CommentBox
:- We invoke
<CommentForm />
- We pass to its previously created
addComment
prop the_addComment
method (which is responsible for adding comments to the state):<CommentForm addComment={this._addComment.bind(this)} />
- We invoke
Another example for the delete comment functionality:
- Delete events are fired from the
Comment
component, but the_deleteComment()
event handler is defined on the parent componentCommentBox
- How can we pass to the child component the ability to trigger the delete functionality? We do it by defining a prop, by including
onDelete={this._deleteComment.bind(this)}
in the_getComments()
return statement - This way, we are sending
this._deleteComment
as an argument to the child component - In
Comment
's delete handler, we'll callthis.props.onDelete(<arg>)
to access the parent's method
Example
CommentBox component
/* ------------------------------------
CommentBox
------------------------------------ */
class CommentBox extends React.Component {
constructor() {
super();
this.state = {
showComments: false,
comments: []
};
}
componentWillMount() {
this._fetchComments();
}
render() {
const comments = this._getComments();
return(
<div className="comment-box">
<CommentForm addComment={this._addComment.bind(this)} />
<CommentAvatarList avatars={this._getAvatars()} />
{this._getPopularMessage(comments.length)}
<h3 className="comment-count">{this._getCommentsTitle(comments.length)}</h3>
<div className="comment-list">
{comments}
</div>
</div>
);
}
_getAvatars() {
return this.state.comments.map(comment => comment.avatarUrl);
}
_getPopularMessage(commentCount) {
const POPULAR_COUNT = 10;
if (commentCount > POPULAR_COUNT) {
return (
<div>This post is getting really popular, dont miss out!</div>
);
}
}
_getComments() {
return this.state.comments.map((comment) => {
return (<Comment
id={comment.id}
author={comment.author}
body={comment.body}
avatarUrl={comment.avatarUrl}
onDelete={this._deleteComment.bind(this)}
key={comment.id} />);
});
}
_getCommentsTitle(commentCount) {
if (commentCount === 0) {
return 'No comments yet';
} else if (commentCount === 1) {
return '1 comment';
} else {
return `${commentCount} comments`;
}
}
_addComment(commentAuthor, commentBody) {
let comment = {
id: Math.floor(Math.random() * (9999 - this.state.comments.length + 1)) + this.state.comments.length,
author: commentAuthor,
body: commentBody,
avatarUrl: 'images/default-avatar.png'
};
this.setState({
comments: this.state.comments.concat([comment])
});
}
_fetchComments() {
$.ajax({
method: 'GET',
url: 'comments.json',
success: (comments) => {
this.setState({ comments });
}
});
}
_deleteComment(commentID) {
const comments = this.state.comments.filter(
comment => comment.id !== commentID
);
this.setState({ comments });
}
}
/* ------------------------------------
CommentForm
------------------------------------ */
class CommentForm extends React.Component {
constructor() {
super();
this.state = {
characters: 0
};
}
render() {
return (
<form className="comment-form" onSubmit={this._handleSubmit.bind(this)}>
<label>New comment</label>
<div className="comment-form-fields">
<input placeholder="Name:" ref={c => this._author = c} />
<textarea placeholder="Comment:" ref={c => this._body = c} onChange={this._getCharacterCount.bind(this)}></textarea>
</div>
<p>{this.state.characters} characters</p>
<div className="comment-form-actions">
<button type="submit">
Post comment
</button>
</div>
</form>
);
}
_getCharacterCount(e) {
this.setState({
characters: this._body.value.length
});
}
_handleSubmit(event) {
event.preventDefault();
if (!this._author.value || !this._body.value) {
alert('Please enter your name and comment.');
return;
}
this.props.addComment(this._author.value, this._body.value);
this._author.value = '';
this._body.value = '';
this.setState({ characters: 0 });
}
}
/* ------------------------------------
CommentAvatarList
------------------------------------ */
class CommentAvatarList extends React.Component {
render() {
const { avatars = [] } = this.props;
return (
<div className="comment-avatars">
<h4>Authors</h4>
<ul>
{avatars.map((avatarUrl, i) => (
<li key={i}>
<img src={avatarUrl} />
</li>
))}
</ul>
</div>
);
}
}
/* ------------------------------------
Comment
------------------------------------ */
class Comment extends React.Component {
constructor() {
super();
this.state = {
isAbusive: false
};
}
render() {
let commentBody;
if (!this.state.isAbusive) {
commentBody = this.props.body;
} else {
commentBody = <em>Content marked as abusive</em>;
}
return(
<div className="comment">
<img src={this.props.avatarUrl} alt={`${this.props.author}'s picture`} />
<p className="comment-header">{this.props.author}</p>
<p className="comment-body">{commentBody}</p>
<div className="comment-actions">
<RemoveCommentConfirmation onDelete={this._handleDelete.bind(this)}/>
<a href="#" onClick={this._toggleAbuse.bind(this)}>Report as Abuse</a>
</div>
</div>
);
}
_toggleAbuse(event) {
event.preventDefault();
this.setState({
isAbusive: !this.state.isAbusive
});
}
_handleDelete() {
this.props.onDelete(this.props.id);
}
}
/* ------------------------------------
RemoveCommentConfirmation
------------------------------------ */
class RemoveCommentConfirmation extends React.Component {
constructor() {
super();
this.state = {
showConfirm: false
};
}
render() {
let confirmNode;
if (this.state.showConfirm) {
return (
<span>
<a href="" onClick={this._confirmDelete.bind(this)}>Yes </a> - or - <a href="" onClick={this._toggleConfirmMessage.bind(this)}> No</a>
</span>
);
} else {
confirmNode = <a href="" onClick={this._toggleConfirmMessage.bind(this)}>Delete comment?</a>;
}
return (
<span>{confirmNode}</span>
);
}
_toggleConfirmMessage(e) {
e.preventDefault();
this.setState({
showConfirm: !this.state.showConfirm
});
}
_confirmDelete(e) {
e.preventDefault();
this.props.onDelete()
}
}
Lifecycle methods
Lifecycle methods in React are functions that get called while the component is rendered for the first time or about to be removed from the DOM. Common lifecycle methods:
componentWillMount()
-- called before a component is renderedcomponentDidMount()
-- called after a component is renderedcomponentWillUnmount()
-- called before a component is removed from the DOM- …
Where mounting = rendering for the first time.
var myArray = ["Lorem", "ipsum", "dolor sit amet", "consectetuer", "adipiscing elit."];
var cloneArray = [...myArray, 'plus one'];
console.log(`
${cloneArray}
${typeof(cloneArray)}
${myArray.indexOf('ipsum')}
`);
// Lorem,ipsum,dolor sit amet,consectetuer,adipiscing elit.,plus one
// object
// 1
- By default, React DOM escapes any values embedded in JSX before rendering them
- JSX represents objects
Controlled components
Controlled components are the preferred way to handle input elements in React.
In HTML, form elements such as
<input>
,<textarea>
, and<select>
typically maintain their own state and update it based on user input. In React, mutable state is typically kept in thestate
property of components, and only updated withsetState()
.
We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
The alternative way to control input elements is uncontrolled Components