Author: Zen and the Art of Computer Programming
1. Background Introduction
React is a JavaScript library for building user interfaces, created and open sourced by Facebook. Like other JavaScript frameworks, React’s biggest feature is that it is easy to use and can easily implement various functions. React is not only a front-end framework, it is also a full-stack solution, including back-end services, databases, and even Including unit testing, etc. Therefore, React also has strong practicality. However, due to the steep learning curve, it is often difficult for beginners to fully master all its features. Therefore, the author of this article starts from the underlying principles of React and analyzes the basic concepts, operating mechanisms, core algorithms and details of React in a simple and easy-to-understand manner. Through a large number of code examples, the author explains the application scenarios and actual operation steps of React in actual projects.
2. Core concepts and connections
What is React?
React (Reactive, reactive) is a JavaScript library for building user interfaces (UI). It is designed for declarative programming, which only describes how the application should look, but not how to update or render these elements.
What is Redux?
Redux is a JavaScript state container that provides predictable state management. It allows you to store all of your application’s state in a single repository instead of multiple separate stores. Redux provides a complete solution, including creating stores, defining actions and reducers, and asynchronous data stream processing based on Redux.
The relationship between React and Redux
React itself is just a library, while Redux is a state manager responsible for storing and modifying the application’s data. React can work with Redux, but they are still closely related. Generally speaking, when React is used as a UI framework, we will use Redux to manage the state of the application; if React is only used for the display of small components, or there is no too complex interaction logic, then React itself can also manage the state.
3. Detailed explanation of core algorithm principles, specific operation steps and mathematical model formulas
Use React to make a simple front-end page
Suppose we already have an HTML file and a JS file. We want to insert a button into HTML and execute a function when the button is clicked. As shown below:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>React App</title> <script src="//i2.wp.com/unpkg.com/react@17/umd/react.development.js"></script> <script src="//i2.wp.com/unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <script src="//i2.wp.com/cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.1/babel.min.js"></script> </head> <body> <button id="myBtn">Click me!</button> <div id="root"></div> <!-- index.js --> <script type="text/babel" src="./index.js"></script> </body> </html>
The content of index.js
is as follows:
class App extends React.Component { handleClick = () => { console.log('Clicked!'); } render() { return ( <div> <h1>Hello World</h1> <button onClick={this.handleClick}>Click me!</button> </div> ); } } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
In this way, we have completed a most basic React application. However, this example is not enough, because we only learned some basic syntax of React, such as introducing libraries, class components and component life cycle. Next we will introduce these syntaxes in detail.
JSX syntax
React uses JSX to define the structure of components. In the above example, we use the ES6 class syntax, which is somewhat similar to traditional object-oriented programming (Object-Oriented Programming, OOP). But JSX is closer to HTML in JavaScript, making writing components more intuitive. For example, in the above example, the
tag can be created using JSX.
return ( <div> <h1>Hello World</h1> <button onClick={this.handleClick}>Click me!</button> </div> );
Only JavaScript expressions can appear in JSX, and JavaScript statements cannot be used directly. For example, if
statements, loop statements, etc. cannot be used. If you need to use these statements, you can only write them as JavaScript functions:
function myFunc(num) { if (num > 0) { return num; } else { return -num; } } // use let result = myFunc(-10); // result is -10
How to import components
One of the ideas behind React modularity is to split the UI into independent reusable components. We can define components in multiple JSX files and then reference them in the current file. But by default, React puts all JSX in the same file, so we can’t load a module on demand. To solve this problem, we need to use Webpack or Browserify to build the bundled files and then deploy them to production.
import React from'react'; import ReactDOM from'react-dom'; import HelloWorld from './components/HelloWorld'; import MyButton from './components/MyButton'; const rootElement = document.getElementById('root'); ReactDOM.render( <> <HelloWorld /> <br /> <MyButton label="Click Me!" onClick={() => alert('clicked')} /> </>, rootElement, );
In the above example, we import two components HelloWorld
and MyButton
, and then render them to the root node #root
. Note that the component name and file name must be consistent!
Component life cycle
React provides many lifecycle methods for monitoring different stages of components. We can use these methods to initialize, update, render and other operations of state.
componentDidMount method
This method is called after the component is rendered for the first time, at which time the DOM node or subcomponent can be obtained. Commonly used for operations such as requesting data:
componentDidMount() { fetch('/api/data') .then((response) => response.json()) .then((data) => this.setState({ data })) .catch(() => this.setState({ error: true })); }
componentDidUpdate method
This method is called immediately after the component is updated. The parameters prevProps
and prevState
represent the previous properties and state respectively. Usually used to synchronize props updates.
componentWillUnmount method
This method is called before the component is uninstalled and is usually used to clear timers, cancel network requests, etc.
Props and State
React components are reactive, which means they automatically re-render when the props or state they depend on change. Props are the configuration items of a component, which are properties passed in from the outside. They are immutable. State can be modified arbitrarily inside the component. It is an object similar to props and is also immutable.
We can get the props and state of the current component through this.props
and this.state
.
class Greeting extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } incrementCount = () => { this.setState({count: this.state.count + 1}); } render() { const { name } = this.props; const { count } = this.state; return ( <div> <p>{name}, you clicked {count} times.</p> <button onClick={this.incrementCount}>Increment Count</button> </div> ) } }
Event Handling
React binds event handlers through JSX event handlers. For example, , the
onClick
attribute value here represents the bound event, the value is a function, and the specific event processing logic is implemented within the function body. .
React supports multiple event types, such as onClick
, onMouseDown
, onChange
, etc.
<button onClick={() => alert('clicked!')}>Click me</button>
Conditional rendering
React supports three conditional rendering methods: if
statement, & amp; & amp;
operator and ternary operator.
{condition & amp; & amp; <Child />} <span>{'Hello, '}{name}</span>
In the first conditional rendering example, the Child component is rendered only when condition is true, otherwise null is returned. In the second conditional rendering example, text is rendered based on whether name exists.
List rendering
React can render arrays and iterators, allowing collection data to be rendered item by item.
const numbers = [1, 2, 3]; const mappedNumbers = numbers.map((number) => <li key={number}>{number}</li>); return <ul>{mappedNumbers}</ul>;
In the above example, the array numbers is converted into JSX form, and then the map function is used to generate a new JSX array. Each JSX object has a unique key attribute, and React uses keys to track which items have been changed, added, or deleted, further optimizing rendering performance.
Function component vs class component
React has two types of components: function components and class components. A function component is a pure function that receives props and returns a JSX element. A class component is a React component with lifecycle methods, and its instance contains state and some business logic.
Class components are often used with Redux to provide a unified state management solution. Functional components are suitable for simple components and do not require lifecycle methods.
Create Redux Store
Redux Store is a place where data is stored, including all state of the application. In Redux, Store is an object that contains the following three main properties:
- State: a plain JavaScript object used to save the application’s state tree
- Reducer: a function that receives the old state and action and returns the new state
- Dispatch: a function used to trigger the reducer, issue an action, and change the state
import { createStore } from'redux'; const initialState = { count: 0 }; function counterReducer(state = initialState, action) { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; default: return state; } } const store = createStore(counterReducer);
In the above example, a Redux Store is created, and the initial state is initialized to { count: 0 }
. The Reducer function receives the old state and action and returns the new state. The createStore
method accepts a reducer function as a parameter and returns a Redux Store instance.
Connecting React and Redux
React-Redux is an officially maintained library that provides the connect method for connecting React components and Redux Store.
import React from'react'; import { connect } from'react-redux'; class Counter extends React.Component { handleIncrement = () => { this.props.dispatch({ type: 'INCREMENT' }); } render() { const { count } = this.props; return ( <div> <h1>Counter</h1> <p>{count}</p> <button onClick={this.handleIncrement}> + </button> </div> ); } } const mapStateToProps = (state) => ({ count: state.count }); export default connect(mapStateToProps)(Counter);
In the above example, we defined a Counter class, which inherits from React.Component. We trigger the INCREMENT action through the dispatch method. Then we map the count data in the Store to the props of the component through mapStateToProps. Finally, we connect the component to the Redux Store using the connect method.
Async Actions with Redux Thunk
Redux Thunk is a third-party middleware in Redux that provides support for asynchronous Action Creator. Using Thunk, you can operate asynchronous actions just like synchronous actions, including delayed execution, cancellation, error handling, etc.
import axios from 'axios'; import thunk from'redux-thunk'; import { createAction, createThunkAction } from '@reduxjs/toolkit'; const loadData = createThunkAction('LOAD_DATA', async () => { try { const response = await axios.get('http://example.com/data'); return response.data; } catch (error) { throw new Error('Failed to load data'); } }); const initialState = { loading: false, data: undefined }; const reducer = (state = initialState, action) => { switch (action.type) { case 'LOAD_DATA/pending': return {...state, loading: true }; case 'LOAD_DATA/fulfilled': return {...state, loading: false, data: action.payload }; case 'LOAD_DATA/rejected': return {...state, loading: false, error: action.error }; default: return state; } }; const middleware = [thunk]; const store = configureStore({ reducer, middleware, }); store.dispatch(loadData());
In the above example, we use the createThunkAction method to create an asynchronous Action Creator. In Action Creator, we use async / await keywords to load data asynchronously. Then, we use the redux-thunk middleware to catch the error and send the appropriate action.