React basic learning notes (I)
- Reference: Teacher Wang Hongyuan's React
React features – declarative programming
- Declarative programming:
- Declarative programming is the mode of the whole front-end development: Vue, React, fluent and SwiftUI;
- It allows us to only maintain our own state. When the state changes, React can render our UI interface according to the latest state;
React development dependency
- The development of React must rely on three libraries:
- React: contains the core code necessary for react
- React DOM: the core code required for react rendering on different platforms
- babel: a tool for converting jsx into React code
- The first contact with react will be confused by its cumbersome dependence. For Vue, we just rely on a Vue JS file, but react actually depends on three libraries.
- In fact, the three libraries perform their own duties, so that each library can only do its own things:
- Before version 0.14 of react, there was no concept of react DOM, and all functions were included in react.
- Why split? The reason is react native.
- The react package contains the core code shared by react and react native.
- React DOM does different things for web and native:
- web side: react DOM will say that jsx will eventually be rendered into a real Dom and displayed in the browser
- Native side: react DOM will say that jsx will eventually render into native controls (such as Button in Android and UIButton in iOS).
Introduce React dependency
- Add these three dependencies:
- Method 1: direct CDN introduction
- Method 2: after downloading, add local dependencies
- Method 3: manage through npm
- For the time being, we will directly introduce CDN to practice the following example program:
- Here is a crossorigin attribute. The purpose of this attribute is to get the error information of the cross domain script
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
Hello World
- Step 1: display a Hello World through React on the interface
- Note: in the script code of React, we must add type="text/babel" to enable babel to parse the syntax of jsx
- ReactDOM.render function:
- Parameter 1: pass the content to be rendered, which can be HTML elements or React components
- Here we pass in an h2 element, and then we will use the React component
- Parameter 2: which HTML element will the rendered content be mounted on
- Here, we have proposed to define a div with id app
- We can introduce external variables or expressions through {} syntax
- Parameter 1: pass the content to be rendered, which can be HTML elements or React components
<body> <div id="app"> </div> <!-- add to React Dependence of --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <!-- Start development --> <!-- matters needing attention: use jsx, And hope script Medium jsx The code is parsed, Must be script Add an attribute to the tag --> <!-- jsx characteristic: Outermost layer of multiple labels(root)There can only be one label --> <script type="text/babel"> let message = "Hello World"; function btnClick() { message = "Hello React"; console.log(message); render(); } // <h2>< / H2 >: JSX code function render() { ReactDOM.render( <div> <h2>{message}</h2> <button onClick={btnClick}>Change text</button> </div>, document.getElementById("app") ); } render(); </script> </body>
Hello React – component development
-
You can first encapsulate the previous business logic into a component, and then pass it into reactdom The first parameter in the render function;
- Here, we temporarily use class to encapsulate components:
- 1. Define a class (class name is capitalized, component name must be capitalized, and lowercase will be regarded as HTML element), which is inherited from react Component
- 2. Implement the render function of the current component
- The jsx content returned in render is the content that React will help us render later
Componentization - data dependency
- The data in the component can be divided into two categories:
- Data involved in interface update: when the data variable is, the content rendered by the component needs to be updated
- Data that does not participate in the interface update: when the data variable is, there is no need to update the content that will be constructed and rendered
- The data participating in the interface update can also be called participating data flow, which is defined in the state of the current object
- We can use this in the constructor State = {defined data}
- When our data changes, we can call this Setstate to update the data, and notify React to perform the update operation
- During the update operation, the render function will be called again and the interface will be rendered with the latest data.
Componentization – event binding
- Componentization problem 2: this in event binding
- Directly define a function in the class and bind this function to the html native onClick event. Who does this function point to?
- It is undefined by default
- It's strange that it's undefined;
- Because in normal DOM operations, this in the listening function is actually a node object (for example, a button object);
- This time, because React is not directly rendered as a real DOM, the button we write is just a syntax sugar, and its essence is the Element object of React;
- When listening here, the function bound this by react is undefined by default;
- In the bound function, we may want to use the current object, such as executing this Setstate function, you must get this of the current object
- When we pass in a function, we need to bind this function directly
- Similar to the following writing method: < button onclick = {this. Changetext. Bind (this)} > change text < / button >
Complete example of Hello World component
<body> <div id="app"> </div> <!-- add to React Dependence of --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <!-- Start development --> <script type="text/babel"> // Encapsulate App components class App extends React.Component { constructor() { super(); // this.message = "Hello World"; this.state = { message: "Hello World" } } render() { return ( <div> <h2>{this.state.message}</h2> <button onClick={this.btnClick.bind(this)}>Change text</button> </div> ) } btnClick() { // this.message = "Hello React"; // this.state.message = "Hello React"; // console.log(this.state); this.setState({ message: "Hello React" }) } } // Rendering Components ReactDOM.render(<App/>, document.getElementById("app")); </script> </body>
Movie list display
<body> <div id="app"></div> <!-- 1.Introduce dependency --> <script src="../react/react.development.js"></script> <script src="../react/react-dom.development.js"></script> <script src="../react/babel.min.js"></script> <!-- 2.to write React code --> <script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { message: "Hello World", movies: ["Westward Journey", "Inception", "Interstellar crossing", "Wandering the earth"] } } render() { const liArray = []; for (let movie of this.state.movies) { liArray.push(<li>{movie}</li>); } return ( <div> <h2>Movie List 1</h2> <ul> {liArray} </ul> <h2>Movie list 2</h2> <ul> { this.state.movies.map((item) => { return <li>{item}</li> }) } </ul> </div> ) } } ReactDOM.render(<App />, document.getElementById("app")); </script>
Counter case
<script type="text/babel"> class App extends React.Component { constructor(pops) { super(props); this.state = { counter: 0 } } render() { return ( <div> <h2>Current count: {this.state.counter}</h2> <button onClick={this.increment.bind(this)}>+1</button> <button onClick={this.decrement.bind(this)}>-1</button> <img src="" alt=""/> </div> ) } increment() { this.setState({ counter: this.state.counter + 1 }) } decrement() { this.setState({ counter: this.state.counter - 1 }) } } ReactDOM.render(<App/>, document.getElementById("app")); </script>
Know JSX
- What is the tag syntax of the assignment to the right of the element variable declaration?
- It is not a string (because it is not wrapped in quotation marks). It looks like a native HTML, but can we assign HTML to a variable directly in js?
- In fact, it is not allowed. If we remove type="text/babel", there will be syntax errors;
- What is it? In fact, it is a jsx syntax;
- What is JSX?
- JSX is a JavaScript syntax eXtension, which is also called JavaScript XML in many places, because it looks like an XML syntax;
- It is used to describe our UI interface, and its completion can be integrated with JavaScript;
- It is different from the module syntax in Vue. You do not need to learn some instructions in the module syntax (such as v-for, v-if, v-else, v-bind);
Why did React choose JSX
- React believes that rendering logic is inherently coupled with other UI logic
- For example, the UI needs to bind events (button, a native, etc.);
- For example, the data status needs to be displayed in the UI, and when some status changes, the UI needs to be changed;
- They are inseparable, so React does not separate tags into different files, but combines them together. This place is Component;
- Writing specification of JSX:
- The top layer of JSX can only have one root element, so we often wrap a div primitive in the outer layer (or use the Fragment we will learn later);
- In order to facilitate reading, we usually wrap a parenthesis () in the outer layer of jsx, which is convenient for reading, and jsx can wrap lines;
- Tags in JSX can be single tags or double tags;
- Note: if it is a single label, it must end with / >;
Use of JSX
Comments in jsx
JSX embedded variables
jsx embedded expression
JSX embedded expression
- Operation expression
- Ternary operator
- Execute a function
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { firstname: "kobe", lastname: "bryant", isLogin: false } } render() { const { firstname, lastname, isLogin } = this.state; return ( <div> {/*1.Operator expression*/} <h2>{ firstname + " " + lastname }</h2> <h2>{20 * 50}</h2> {/*2.Ternary expression*/} <h2>{ isLogin ? "welcome back~": "Please log in first~" }</h2> {/*3.Make a function call*/} <h2>{this.getFullName()}</h2> </div> ) } getFullName() { return this.state.firstname + " " + this.state.lastname; } } ReactDOM.render(<App/>, document.getElementById("app")); </script>
jsx binding properties
- For example, every element has a title attribute
- For example, img elements have src attributes
- For example, the a element will have a href attribute
- For example, an element may need to be bound to a class
- For example, native uses inline style
<body> <div id="app"></div> <script type="text/babel"> function getSizeImage(imgUrl, size) { return imgUrl + `?param=${size}x${size}` } class App extends React.Component { constructor(props) { super(props); this.state = { title: "title", imgUrl: "http://p2.music.126.net/L8IDEWMk_6vyT0asSkPgXw==/109951163990535633.jpg", link: "http://www.baidu.com", active: true } } render() { const { title, imgUrl, link, active } = this.state; return ( <div> {/* 1.Bind common properties */} <h2 title={title}>I'm the title</h2> <img src={getSizeImage(imgUrl, 140)} alt=""/> <a href={link} target="_blank">use Baidu Search</a> {/* 2.Bind class */} <div className="box title">I am div element</div> <div className={"box title " + (active ? "active": "")}>Me too. div element</div> <label htmlFor=""></label> {/* 3.Binding style */} <div style={{color: "red", fontSize: "50px"}}>I am div,binding style attribute</div> </div> ) } } ReactDOM.render(<App />, document.getElementById("app")); </script>
React event binding
- React events are named in camel case instead of pure lowercase;
- We need to pass in an event handling function through {}, which will be executed when the event occurs
- Binding problem of this
- The reason is that we do not call the btnClick function actively, and when the button changes, React calls the btnClick function internally;
- When it is called internally, it does not know how to bind the correct this;
- How to solve this problem?
- Scheme 1: bind displays the bound this to btnClick
- Scheme 2: use ES6 class fields syntax
- Scheme 3: pass in the arrow function during event listening (recommended)
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { message: "How do you do", counter: 100 } this.btnClick = this.btnClick.bind(this); } render() { return ( <div> {/* 1.Scheme 1: bind bind this (display binding) */} <button onClick={this.btnClick}>Button 1</button> <button onClick={this.btnClick}>Button 2</button> <button onClick={this.btnClick}>Button 3</button> {/* 2.Scheme 2: when defining a function, use the arrow function */} <button onClick={this.increment}>+1</button> {/* 2.Scheme three (recommendation): directly import an arrow function and invoke the function to be executed in the arrow function.*/} <button onClick={() => { this.decrement("why") }}>-1</button> </div> ) } btnClick() { console.log(this.state.message); } // increment() { // console.log(this.state.counter); // } // this is never bound in the arrow function // Add attribute to object in ES6: class fields increment = () => { console.log(this.state.counter); } decrement(name) { console.log(this.state.counter, name); } } ReactDOM.render(<App/>, document.getElementById("app")); </script>
Event parameter passing
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { movies: ["Westward Journey", "dominant sea power", "Wandering the earth", "Inception"] } this.btnClick = this.btnClick.bind(this); } render() { return ( <div> <button onClick={this.btnClick}>Button</button> <ul> { this.state.movies.map((item, index, arr) => { return ( <li className="item" onClick={ e => { this.liClick(item, index title="li"> {item} </li> ) }) } </ul> </div> ) } btnClick(event) { console.log("The button was clicked", event); } liClick(item, index, event) { console.log("li Click happened", item, index, event); } } ReactDOM.render(<App/>, document.getElementById("app")); </script>
React conditional rendering
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { isLogin: true } } render() { const { isLogin } = this.state; // 1. Scheme 1: judge by if: there are many logic codes let welcome = null; let btnText = null; if (isLogin) { welcome = <h2>welcome back~</h2> btnText = "sign out"; } else { welcome = <h2>Please log in first~</h2> btnText = "Sign in"; } return ( <div> <div>I am div element</div> {welcome} {/* 2.Scheme 2: ternary operator */} <button onClick={e => this.loginClick()}> <hr /> <h2>{isLogin ? "How do you do, coderwhy": null}< {/* 3.Scheme 3: logic and&& */} {/* Logic and: One condition does not hold, The latter conditions are <h2>{ isLogin && "How do you do, coderwhy" }</h2 { isLogin && <h2>How do you do, coderwhy</h2> } </div> ) } loginClick() { this.setState({ isLogin: !this.state.isLogin }) } } ReactDOM.render(<App />, document.getElementById( </script>
Conditional rendering -v-show effect
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { isLogin: true } } render() { const { isLogin} = this.state; const titleDisplayValue = isLogin ? "block": "none"; return ( <div> <button onClick={e => this.loginClick()}>{isLogin ? "sign out": "Sign in"}</button> <h2 style={{display: titleDisplayValue}}>How do you do, coderwhy</h2> </div> ) } loginClick() { this.setState({ isLogin: !this.state.isLogin }) } } ReactDOM.render(<App />, document.getElementById("app")); </script>
- Example 2:
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { names: ["abc", "cba", "nba", "mba", "dna"], numbers: [110, 123, 50, 32, 55, 10, 8, 333] } } render() { return ( <div> <h2>Name list</h2> <ul> { this.state.names.map(item => { return <li>{item}</li> }) } </ul> <h2>Digital list(Filter 1)</h2> <ul> { this.state.numbers.filter(item => { return item >= 50; }).map(item => { return <li>{item}</li> }) } </ul> <h2>Digital list(Filter 2)</h2> <ul> { this.state.numbers.filter(item => item >= 50).map(item => <l } </ul> <h2>Digital list(intercept)</h2> <ul> { this.state.numbers.slice(0, 4).map(item => { return <li>{item}</li> }) } </ul> </div> ) } } ReactDOM.render(<App />, document.getElementById("app")); </script>
The essence of JSX
- In fact, jsx is just react Syntax of the createElement (component, props,... Children) function.
- All jsx will eventually be converted to react Function call to createElement
createElement needs to pass three parameters:
- Parameter 1: type
- Type of current ReactElement;
- If it is a label element, use a string to represent "div";
- If it is a component element, the name of the component is used directly;
- Parameter 2: config
- All attributes in jsx are stored in config as attributes and values of objects
- Parameter 3: children
- The contents stored in the tag are stored in the form of children array;
- Of course, what if it's multiple elements? React processes them internally
Babel official website
- We know that the default jsx uses babel to help us with syntax conversion, so the jsx code we wrote before needs to rely on babel.
- You can quickly view the conversion process on babel's official website: https://babeljs.io/repl/#?presets=react
Write jsx code directly
- We'll write react ourselves CreateElement Code:
- We didn't write through jsx, and the interface can still be rendered normally.
- In addition, in this case, do you still need babel related content? I don't want it any more
- Therefore, type="text/babel" can be deleted by us;
- Therefore, < script SRC = ".. / react / Babel. Min.js" > < / script > can be deleted by us
Creation process of virtual DOM
- We passed react CreateElement finally creates a ReactElement object:
- What is the function of this ReactElement object? Why did React create it?
- The reason is that React uses the ReactElement object to form a JavaScript object tree;
- The object tree of JavaScript is the famous Virtual DOM (Virtual DOM);
- How to view the tree structure of ReactElement?
- We can print the previous jsx returned results;
- Pay attention to the printing of jsx in the following code;
- The tree structure finally formed by ReactElement is Virtual DOM;
Why use virtual DOM
- Why adopt virtual DOM instead of directly modifying real DOM?
- It is difficult to track the change of state: in the original development mode, it is difficult for us to track the change of state, which is inconvenient to debug our application;
- The performance of operating real DOM is low: the traditional development mode will perform frequent DOM operations, and the performance of this method is very low;
- DOM operation performance is very low:
- First, document CreateElement itself creates a very complex object;
- https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createElement
- Secondly, DOM operation will cause browser backflow and redrawing, so frequent DOM operation should be avoided in development;
Declarative programming
- Virtual DOM helped us move from imperative programming to declarative programming
- React official statement: Virtual DOM is a programming concept.
- In this concept, the UI is stored in memory in an idealized or virtualized way, and it is a relatively simple JavaScript object
- We can use reactdom Render synchronizes the virtual DOM with the real dom. This process is called Reconciliation
- This programming method gives React a declarative API:
- You just need to tell React what state you want the UI to be;
- React to ensure that the DOM matches these states;
- You don't need to directly operate the DOM, but can only be liberated from manually changing the DOM, attribute operation and event handling;
Stage exercise example
- Main code:
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { books: [ { id: 1, name: '<Introduction to Algorithms', date: '2006-9', price: 85.00, count: 2 }, { id: 2, name: '<UNIX Programming art', date: '2006-2', price: 59.00, count: 1 }, { id: 3, name: '<Programming Pearl', date: '2008-10', price: 39.00, count: 1 }, { id: 4, name: '<Code collection', date: '2006-3', price: 128.00, count: 1 }, ] } } renderBooks() { return ( <div> <table> <thead> <tr> <th></th> <th>Book name</th> <th>Publication date</th> <th>Price</th> <th>Purchase quantity</th> <th>operation</th> </tr> </thead> <tbody> { this.state.books.map((item, index) => { return ( <tr> <td>{index+1}</td> <td>{item.name}</td> <td>{item.date}</td> <td>{formatPrice(item.price)}</td> <td> <button disabled={item.count <= 1} onClick={e => this.changeBookCount(index, -1)}>-</button> <span className="count">{item.count}</span> <button onClick={e => this.changeBookCount(index, 1)}>+</button> </td> <td><button onClick={e => this.removeBook(index)}>remove</button></td> </tr> ) }) } </tbody> </table> <h2>Total price: {this.getTotalPrice()}</h2> </div> ) } renderEmptyTip() { return <h2>Shopping cart is empty~</h2> } render() { return this.state.books.length ? this.renderBooks(): this.renderEmptyTip(); } changeBookCount(index, count) { const newBooks = [...this.state.books]; newBooks[index].count += count; this.setState({ books: newBooks }) } removeBook(index) { // Design principle in React: immutability of data in state; this.setState({ books: this.state.books.filter((item, indey) => index != indey) }) } getTotalPrice() { // 1.for loop mode // let totalPrice = 0; // for (let item of this.state.books) { // totalPrice += item.price * item.count; // } // return formatPrice(totalPrice); // 2. Filter / map / reduce // Parameters of callback function: // Parameter 1: the result of the last callback function (the result of the callback function without the last function for the first time, using the initialization value) const totalPrice = this.state.books.reduce((preValue, item) => { return preValue + item.count * item.price; }, 0); return formatPrice(totalPrice); } } ReactDOM.render(<App/>, document.getElementById("app")); </script>