This post contains my notes about the React basics that I learned by doing the Intro to React tutorial. Text will also contain simple code snippets to demonstrate the described aspects.
I am at the beginning of a journey to master React. The purpose of the text is to deepen my understanding of the concepts that I learned by writing about them (technique proposed on this skutecznyprogramista.pl blog post). There are many more React features and techniques that are not covered here at all - this post is all about the total basics 🙂.
What is React
Let’s start with basics. As stated in the tutorial:
React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
An important thing to note here is that React is a JavaScript library, not a framework. And it specifically is designed for building UI. So for example React will not enforce what library you should use to make an http request. It will also not tell you how to build the whole application. It focuses only on building the UI layer.
The second part of React definition introduces us to the concept of component.
[React] lets you compose complex UIs from small and isolated pieces of code called “components”.
We use components to describe the elements that we want to see in the UI. By combining many components, we create whole UI. Each component takes in parameters called props
, that we use to pass data to components. This makes them generic and reusable.
Function and class components
In practice, React components are either defined as classess or functions.
This is how a function component looks:
function Button(props) {
return <button className="btn">{props.displayText}</button>;
}
By convention PascalCase is used for writing component names. This component renders a button that displays text passed in the displayText
prop value. The button has also a btn
CSS class. Below is the same component definition, but described with class syntax:
class Button extends React.Component {
render() {
return <button className="btn">{this.props.displayText}</button>;
}
}
Each class component must have a render()
method, in which we have to return the component view description. Also, when referring to the instance properties we have to remember to use the this
keyword.
One of the reasons for using class syntax is to create stateful components. This is described in later section in this post.
JSX
The returned value which looks like HTML is actually a special syntax called JSX. During build it is transformed to JavaScript. In JSX within the braces we can put any JavaScript expression, e.g.:
<div>{props.number % 2 == 0 ? "Even" : "Odd"}</div>
This code will print either Even or Odd depending on the number
prop passed to the component.
Using components and passing data as props
Declaring a component is like creating a new custom HTML tag which we can use. Thus to use the component we can simply refer to it within return value of other (parent) component:
function App(props) {
return (
<div>
<p>My awesome app</p>
<Button displayText="Useless button" />
</div>
);
}
As shown, we use key-value pairs for passing data as props. The syntax looks somewhat similar to adding a HTML attribute. In the example above, we are adding a displayText
prop with a string value of Useless button
. If the component props change, React will automatically re-render the component and its children to reflect the changed view.
We can pass any other values through props, e.g. numbers, boolean values, arrays and even objects:
<Summary show={true} characterLimit={500} options={{ language: 'en', addEllipsis={false} }} />
There is important concept to know - the props can be passed from parent component to its children components, but not the other way around. This is called one-way data flow.
Simple interaction
In React we can easily define handlers that we want to invoke when particular event occurs. Here is an example:
function Button(props) {
return (
<button className="btn" onClick={() => console.log("Clicked!")}>
{props.displayText}
</button>
);
}
When user clicks the button, the event handler function invokes and logs Clicked! in the console.
Stateful components
A React component can have its own private state. State is an object that holds some data about the given component instance. To define a stateful component, we need to define it using the class syntax.
This is how we introduce a state to component:
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
timesClicked: 0,
};
}
render() {
return (
<button className="btn">
{this.props.displayText} {this.state.timesClicked}
</button>
);
}
}
Initial state is defined within the class constructor. In this example we are defining new timesClicked
property in the state and assigning 0
as its initial value. We are also displaying this value inside the button.
Updating state
To update the component state, we need to invoke special this.setState()
method. As an argument, we need to pass the object with the new values of properties which we want to update. Here is an example of updating the state when clicking on the button:
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
timesClicked: 0,
};
}
render() {
return (
<button
className="btn"
onClick={() =>
this.setState({ timesClicked: this.state.timesClicked + 1 })
}
>
{this.props.displayText} {this.state.timesClicked}
</button>
);
}
}
In the onClick
handler we are incrementing the timesClicked
state property. When state changes, React also re-renders the component and it’s children, similarly as it does in case of prop change.
Interaction between components
We have seen that we can pass data from parent component to its children using props. But sometimes the interaction is more complex. Let’s imagine that we want to have two sibling components - Button
and Display
- that are both children of Parent
component. Display
should show how many times Button
was clicked. But in React we cannot pass props between sibling components, and they are also not aware of its own states. So how to do it?
In that case we can lift the state up to the parent component. The state of parent will hold the number of times the button was clicked, and this state will be updated after next click. The state will be shared with the child components through props. So the children components will depend on the parents state, but will not interact between each other at all.
Passing state from Parent
to Display
using props is easy. But how to update Parent
’s state when Button
is clicked? To do it, firstly we need to create a function within Parent
that will handle updating the state. Secondly, we need to pass this function as a prop to Button
. Lastly, within Button
, we need to call this function when it’s clicked. Let’s see how the code looks:
Parent component:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
timesClicked: 0,
};
}
handleClick() {
this.setState({ timesClicked: this.state.timesClicked + 1 });
}
render() {
return (
<div>
<Button onClick={() => this.handleClick()} />
<Display value={this.state.timesClicked} />
</div>
);
}
}
We do not need any state in the child components, so we can use the shorter function syntax when we declare them.
Button component:
function Button(props) {
return <button onClick={props.onClick}>Click me!</button>;
}
Display component:
function Display(props) {
return <div>{props.value}</div>;
}
Dynamic lists in React
Lastly I want to mention two things about lists in React.
Rendering lists
Firstly, let’s see how to render a dynamic list that will reflect values from an array. To do it we can map through the array and return list the JSX item description for each element. Map will return a new array of these descriptions, and React will simply render them.
function List(props) {
return (
<ul>
{props.employees.map(employee => (
<li key={employee.employeeId}>{employee.name}</li>
))}
</ul>
);
}
In this example the List
component receives an employees
prop.
Its value is an array of objects with name
and employeeId
properties:
<List
employees={[
{ name: "Amy", employeeId: 5 },
{ name: "John", employeeId: 11 },
{ name: "Bob", employeeId: 23 },
]}
/>
List key
Each dynamically generated list item has to receive a key
prop. If we skip this, we will get an error in the browser console.
The purpose of key is to provide extra data that React uses to detect which element should be re-rendered if the data changes. The keys should be unique (within the given list) and should not change for specific list item over time. By default React will use array element index as a key, but we should avoid it since indices could change when the list data is modified.
Next steps
The Intro to React tutorial was quite short, but at the same time introduced the basic React concepts in very simple way. But it did not cover all React aspects, so the next step is to dive deeper and get more understanding about this library.