ReactJS Frontend
Written with reference to ReactJS Documentation and various online resources.
(1) Introduction
Big Overview of ReactJS
- A JavaScript library for building user interfaces.
- Component based: Each component has its own set of variable values to maintain, otherwise known as states. Smaller components can be composed to form complex UIs. For eg, the Welcome Landing Page forms the big outer component. It could be composed of smaller components such as Search Bar Filter, Page Buttons, Navigation Bar. Each of these components have to display a certain set of values and respond to users’ actions. These are managed by the components’ individual states.
- Functional and Class Components: Different coding styles for creating components. With the introduction of React Hooks, functional components are preferred. It offers a more concise and cleaner way of writing code.
ReactJS-Redux
- If you find that you have high coupling between different components whereby you have to pass states from one component to many more components back and forth, then it might be time to consider using Redux. Redux offers a way to store state in a common store accessible by all components instead of storing them in the individual components and passing states around which increases the complexity of the code.
- This is an optional choice depending on your project use case.
You may have heard of React Native. What is the difference between ReactJS and React Native?
- ReactJS is a JavaScript library used for creating UIs. React Native is a cross-platform that allows one to build mobile application.
(2) Set Up
Before going on to the next few sections, follow the above link to learn how to set up a React app with just a few steps on your computer. Take a look at the boiler plate code and see how the different parts combine together.
(3) Basic Concepts
This section will attempt to explain some basic concepts of React.
Concept 1: Render() method
Class Components
This method takes in an input data called Props and returns React elements to display. In the code below we see a class component called HelloMessage
.
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}
This class component is used by React using the following code where the props is passed in by name=”Taylor”.
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('hello-example')
);
Functional Components
Note the different syntaxes.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}ReactDOM.render(
<App />,
document.getElementById('root')
);
Concept 2: Props, Pure functions
All React components must act like pure functions with respect to their Prop values. Components do not change their inputs and always return the same result for the same given input. This hence gives rise for the need of state because most times, we might need to implement logic and display results differently from the received props.
Concept 3: State in Class Components, as explained below
Previously, we know that in order to change the displayed value, we will need to call the render method and update the props value being passed into a component. We keep doing this whenever we want to make a change and have to call render several times. However, ideally we only need to call the render method once and let the component update its own UI display value. We might want to leave the logic up to the component to manage. Hence, we need to add state
to the component.
State
allows React components to change their output over time in response to user actions, network responses, and anything else, without violating the rule that components must act like pure functions.
State is similar to props except that it is encapsulated and fully managed by the component.
this.state value is now initialised in the constructor method.
If we want to modify the values of state, we have a method called setState()
Concept 4: Props and states
One thing to note is that this.props and this.state may not be updated asynchronously. Hence, we should not rely on their values for calculating the next state.
Instead, we can use a second form of setState() to accept a function rather than an object. The function receives the previous state as the first argument, and the props at the same time the update is applied as the second argument.
You can also choose to pass a state as props to another component (termed as child component).
Concept 5: Lifecycle Methods in Class Components
Lifecycle Methods provides a way to free up resources taken by the components when they are destroyed.
componentDidMount()
componentWillUnmount()
componentDidUpdate()
Mounting: In the first rendering of the Clock component to the DOM, we want to set up a timer.
Unmounting: Whenever the Clock DOM is destroyed, we also clear the timer.
We have lifecycle methods to handle these in class components.
The componentDidMount() method runs after the component output has been rendered to the DOM. This is a good place to set up a timer (initiate API calls). We can also create more state fields in this method using this.state. We can setState() here and cause another rendering but this will happen before the browser updates the UI.
The ComponentWillUnmount() method will run when the DOM is removed.
Big Picture:
Let’s quickly recap what’s going on and the order in which the methods are called:
- When
<Clock />
is passed toReactDOM.render()
, React calls the constructor of theClock
component. SinceClock
needs to display the current time, it initializesthis.state
with an object including the current time. We will later update this state. - React then calls the
Clock
component’srender()
method. This is how React learns what should be displayed on the screen. React then updates the DOM to match theClock
’s render output. - When the
Clock
output is inserted in the DOM, React calls thecomponentDidMount()
lifecycle method. Inside it, theClock
component asks the browser to set up a timer to call the component’stick()
method once a second. - Every second the browser calls the
tick()
method. Inside it, theClock
component schedules a UI update by callingsetState()
with an object containing the current time. Thanks to thesetState()
call, React knows the state has changed, and calls therender()
method again to learn what should be on the screen. This time,this.state.date
in therender()
method will be different, and so the render output will include the updated time. React updates the DOM accordingly. - If the
Clock
component is ever removed from the DOM, React calls thecomponentWillUnmount()
lifecycle method so the timer is stopped.
componentDidUpdate() is invoked as soon as the updating happens. It is used to update DOM in response to props or state changes. setState() is allowed to be called here but it is important to wrap it in a condition to check for state or prop changes from the previous state (if found that there is no change in props, there wont be any api calls), otherwise there might be an infinite loop.
There are many other lifecycle methods not commonly used as seen below.
render() is the most commonly used lifecycle method. It is a pure function. set state is not allowed.
componentDidMount() happens right after your component is mounted. You can set state here but with caution.
componentDidUpdate() happens right after any updating happens. You can set state here but with caution.
componentWillUnmount() happens just before the component unmounts and is destroyed. This is a good place to cleanup all the data. You cannot set state here.
Concept 6: Event Handlers
Components need to be able to respond to user actions such as user clicks.
In order to be responsive to user actions, we need to provide a listener to a DOM element when the component is rendered. We do this by binding it in the constructor.
We can pass arguments to Event Handlers in the following way.
Concept 7: Hooks in functional components
The discussion of concepts so far has been mostly with respect to class components. Now we will introduce some commonly used Hooks in functional components.
Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes.
Hooks are JavaScript functions, but they impose two additional rules:
- Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.
- Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions. (There is just one other valid place to call Hooks — your own custom Hooks.
Basic Hooks
- useState
- useEffect
- useContext
Additional Hooks
- useReducer
- useCallback
- useMemo
- useRef
- useImperativeHandle
- useDebugValue
useState
const[currentState, setStateFunction] = useState(initialState)
currentState contains the current state of the element and setState is the function that allows you to modify the state of the element.
setStateFunction(newValueToBeSet)
We just pass in the new value we want to set the variable to be.
The convention is to have 1 useState method for 1 attribute. If you have many attributed, then you can create more than 1 useState method for each of them.
This is because, when you call setState(XXX), the entire state will be overridden by XXX. If your passed in XXX value does not contain all the attributes in the state, there will be a loss of states.…for eg, if the entire state is supposed to have A,B,C but when I call setState, I only set the state for the attribute A, then B and C will have their values lost.
useEffect
This function has the same purpose as the lifecycle methods componentDidMount
, componentDidUpdate
, and componentWillUnmount
previously introduced for class components, but all combined into a single API.
Takes in a function as an argument. This function will be executed by React on every render cycle after the DOM has been rendered. If you do a setState inside useEffect, there might be an infinite loop.
It can also take a second argument which is an array of dependencies. Whenever any of these dependencies are updated, this function will be run again. If no dependencies were passed in, then it means no data will cause the change of this function and useEffect never re-executes. Here then, allows us to do a setState and not fall into an infinite loop.
If you want to do some actions at the end when the component unmounts, such as cleaning, then you can include a return function. Otherwise, the return is optional.
useContext
We can use useContext API to share states among different components. For example, we want to share the theme colour.
The Context’s Provider component can be used to provide the theme to all React child components below this React top-level component which uses the Provider:
Another component for eg component C (not component D which is a child component of the provider) can consume this theme to style itself.
(4) Functional VS Class Components
Syntax: Functional components end up with lesser code and helps to make it easier to read and test.
State: When it was first introduced, functional components were meant to behave just like JS functions and we do not use setState() in them. This is why they are called stateless. If you need a functional component to have state, you either create a class component, pass state from parent component or use the useState hook (which is a new addition in functional components).
(5) Smart VS Dumb Components
Dumb components: Mainly for UI styling and accepts props. It rarely have states for managing application data and mostly is for manipulating the UI.
Smart components: Manage logic and states and focus on how things work. They fetch, capture and pass down data. They are responsible for making API or libraries calls.
The convention was to use functional components for dumb components and class compontents for smart components. But with the introduction of React Hooks for functional components, we can work solely with just functional components.
(6) Redux with React
Redux is simply another technology we can use to work hand in hand with React for management of states when it gets too complex. For instance, you need to keep passing a lot of data back and forth from parent to child to grandchild components etc… However, note that it might be a blessing for some use cases, but an overkill for others.
Check out this super helpful article for more on Redux:
Some concepts:
Store: Holds all of the application’s state
Redux reducer: Just a JS function and takes two parameters which is the current state and action.
Dispatching actions: Sending a signal to the store via the form of JS objects (actions).
Link to the ReactJS Documentation
Reading the documentation is a good way to understand more in depth about React. However, the best way to become a React master is to develop your own web application with React!