When I first started with a front-end framework, I chose Vue, which was faster to use; So far, I have developed several projects based on Vue, and I have a certain understanding of the principle of Vue, which can be said to be “proficient in use” ~ ๐ Recently the project is not too busy, I finally… Decided to learn React!! (Rubbing hands, excited, ๐๐ผ)
โคด๏ธ How to get started: how to get started on the official website + Choose a review of React book ๐
Preparation before starting
React features: virtual DOM, state, one-way data flow, components
- Declarative view layer – a combination of JSX, HTML and JS
- Simple update process — developers only define UI state, React renders
- Flexible rendering implementation – The virtual DOM can be rendered to different terminals in conjunction with other libraries
- Efficient DOM manipulation — virtual DOM
Start the React project:
npm install -g create-react-app // Install create-react-app scaffolding
create-react-app my-app // Create the project
cd my-app/
npm start / / start
Copy the code
Check: create-react-app.dev/docs/gettin…
Compatibility problem node version switching:
sudo n v1415.. 0 // A version number
Copy the code
First, some basic concepts
1, JSX
- WHAT?
JSX is a syntactic extension of Javascript, JSX = Javascript + XML, that is, to write XML in Javascript, because of this feature of JSX, so it has the flexibility of Javascript, At the same time, it is both semantic and intuitive of HTML.
Such as:
function Title(){
return <h1>Im title~~~</h1>;
}
Copy the code
In React, JSX can generate React “elements”. The React element will be explained later.
- According to?
React argues that rendering logic is intrinsically coupled to other UI logic, such as binding events in the UI, notifying the UI when state changes at certain moments, and displaying prepared data in the UI. React implements separation of concerns by storing both together in loosely coupled units called components.
Different from the way VUE separates JS and HTML
- HOW?
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>; // {} can write JS expressions inside
ReactDOM.render(
element,
document.getElementById('root'));// Render the JSX element to the element whose id is root
Copy the code
Suggestion: If JSX has multiple lines, enclose them in parentheses.
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
Copy the code
Babel translates JSX into a function call called react.createElement () that creates the corresponding DOM object:
// This is the simplified structure
const element = {
type: "h1".props: {
className: "greeting".children: "Hello, world!",}};Copy the code
These objects are called React elements. — [JS object]
Note: JSX writes native DOM attributes as className and event names as camel (onclick -> onclick).
2. Element rendering
To render a React element into a DOM node, simply pass them together to reactdom.render (). If the UI is to be updated, reactdom.render () needs to be called again. React only updates the changed part — the virtual DOM & Diff — when re-rendering.
Components & props
There are two ways to write components in React: functions and classes. The first letter of the component must be capitalized.
Function component: if the component only has a render method and no state, it is simpler to write function component.
function MyComp(props) {
return <h1>hello {props.name}</h1>;
}
Copy the code
Class component (equivalent) :
/ / inheritance in React.Com ponent
class MyComp extends React.Component {
constructor(props) {
super(props); // props is the argument received by the component, and super means to execute the constructor of the parent class to complete initialization
}
render() {
// The render method returns the view structure to display -- the React element
return <h1>hello {this.props.name}</h1>; }}Copy the code
In all React components that have constructors, constructors must start with super(props). Otherwise, undefined bugs may occur in the this.props constructor.
Class components must meet two conditions:
class
Inherited fromReact.Component
;class
Internal must be definedrender
Methods;
function App() {
return (
<div>
<MyComp name="A" />{/* The child component will receive */} via this.props. Name<MyComp name="B" />
<MyComp name="C" />
</div>
);
}
Copy the code
When passed to the child component, the child component gets a PROPS object.
Props is the way a parent component passes a value to a child component! It is read-only: All React components must protect their props from being changed like pure functions. We can’t change props directly in a subcomponent.
React provides the PropTypes object for verifying props.
import PropTypes from "prop-types";
PropTypes.propTypes = {
a: PropTypes.object, The a attribute is an object type
b: PropTypes.number, // the b attribute is a numeric type
c: PropTypes.func.isRequired, // Function type, required
};
// defaultProps specifies the default value for the property
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Welcome.defaultProps = {
name: "World"};Copy the code
Component styles: external CSS and inline styles
- tag introduction: applies to all components
- Import introduces: scoped local styles
- Inline style:
<div style={{color: 'red'}}></div>
The first {} indicates that it is a JS expression, the second {} indicates that it is an object inside, and the property name must be in camel form.
4. Life cycle
โ ๏ธ Only class components have lifecycle methods, not function components
The life cycle includes:
- Mount phase, call:
constructor() / /classConstructor method, in whichsuper(props) receiving parameterscomponentWillMount(// The component is called before it is mountedrender(// returns a method defined in the componentReactElement is not responsible for the actual renderingcomponentDidMount() // The component is mounted toDOMCall after, for example, when the back end requests some datasetStateCauses the component to be rerenderedCopy the code
- During the update phase, the props or state of the component changes and is called in sequence:
componentWillReceiveProps(nextProps) // called when props changes, nextProps is the new parameter
shouldComponentUpdate(nextProps, nextState) // Whether to continue the update process, return a Boolean value
// By comparing the old and new values, the method returns false if the old and new values are the same, and subsequent updates are not continued to optimize performance
componentWillUpdate(nextProps, nextState) // Before the update, it was rarely used
render()
componentDidUpdate(prevProps, prevState) // After the component is updated, you can manipulate the updated DOM
Copy the code
- Unloading stage:
componentWillUnmount(){}// Called before the component is deleted to do some cleanup
Copy the code
5, the state
You can set state in a component to store the component’s own data:
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
time: new Date()}; }render() {
return <h1>Its {this.state.time}</h1>; }}Copy the code
Instead of changing state directly, use setState(). React will merge the state we set. React automatically updates its children every time setState is called in a component.
Data flow is one-way ~ only from parent to child.
Immutability: In general, there are two ways to change data. The first way is to modify the value of the variable directly, and the second way is to replace the old data with a new one. React recommends using the second method. Why?
- Simplify complex functions
Immutability makes complex features easier to implement. For example — undo and restore is a common requirement in development, and not directly modifying the data allows us to trace and reuse the history.
- Track changes in data
If you modify the data directly, it is difficult to track the changes. Tracking data changes requires that the mutable object can be compared to the previous version, so that the entire object tree needs to be traversed once.
It is relatively easy to track changes in immutable data. If the object becomes a new object, we can say that the object has changed.
- Determine when to rerender in React
The main advantage of immutability is that it helps us create pure Components in React. We can easily determine if immutable data has changed and thus when to rerender the component.
6. Event handling
React events are named in camel case like this:
<button onClick={activateLasers}> Activate Lasers </button>
Copy the code
Response functions that handle events are assigned to event properties as objects, not strings. Because events in React are synthetic events, not native DOM events.
React has a naming convention that typically names the listener prop representing the Event as on[Event] and the listener method that handles the Event as handle[Event].
Note that this points to the problem in React event handling:
(1) Arrow function
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
time: new Date()}; }handleClick() {
console.log(this.state.time);
}
render() {
return (
<button
onClick={()= >{ this.handleClick(); }} > button</button>); }}// This points to the instance object of the current component
Copy the code
This way, a new event handler is recreated each time Render is called.
(2) Component methods
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
time: new Date()};this.handleClick = this.handleClick.bind(this);
// Bind this method to the current component instance
}
handleClick() {
console.log(this.state.time);
}
render() {
return <button onClick={this.handleClick}>button</button>; }}Copy the code
This way, render calls do not recreate a new event handler, but manually bind this in the constructor.
Alternatively, we could bind this at the same time we assign to the element event attribute:
return <button onClick={this.handleClick.bind(this)}>button</button>
Copy the code
(3) Attribute initialization syntax (ES7)
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
time: new Date()}; } handleClick =() = > {
console.log(this.state.time);
}; // also arrow function
render() {
return <button onClick={this.handleClick}>button</button>; }}Copy the code
Projects created using the official scaffolding Create React App support this feature by default. You can use Babel’s transform-class-properties plugin to support this feature.
Conditional rendering & Lists & Forms
Conditional rendering:
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
Copy the code
List:
const numbers = [1.2.3.4.5];
const listItems = numbers.map((number) = > <li>{number}</li>);
Copy the code
It is recommended that each dynamic list element be given a key: [similar to Vue], otherwise the console will report an error
const listItems = numbers.map((number) = > (
<li key={number.toString()}>{number}</li>
));
Copy the code
Forms: If a form element’s value is managed by React, it is called a controlled component.
1) Text fields — Input elements and Textarea elements of type Text are controlled by setting the value of the form element through its value attribute and listening for changes in value through the onChange event of the form element. And synchronize the changes to the state of the React component.
render(){
return (
<form onSubmit={this.handleSubmit}>
<label>Name:<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
Copy the code
2) Select element — Determines which option element is selected by defining the value attribute on the SELECT.
render() {
return (
<select value='2'>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
);
}
// The element with value 2 is selected
Copy the code
3) Checkboxes and checkboxes — Input elements with type checkbox and radio, React controls the Checked property.
handleSelectChange(event){
this.setState({
[event.target.name]: event.target.checked
})
}
render() {
return (
<label>
<input type="checkbox" value="yes" name="yes" checked={this.state.yes} onChange={this.handleSelectChange}
/>Yes.</label>
<label>
<input type="checkbox" value="no" name="no" checked={this.state.no} onChange={this.handleSelectChange}
/>not</label>
);
}
Copy the code
Using controlled components to handle form state is cumbersome. An alternative is to use uncontrolled components — the form manages its own state and React fetches the form’s value through a ref. This simplifies operations, but breaks the consistency of React’s component state management, so use it sparingly and we’ll skip it here.
8. State improvement
State promotion refers to the promotion of data maintained by multiple child components to the parent component.
handleChange(e) {
this.props.onTemperatureChange(e.target.value); // Triggers an event for the parent component
// Similar to vue's this.$emit
}
Copy the code
When you need to fetch data from multiple child components at the same time, or two components need to communicate with each other, you need to promote the child’s state data to its common parent. The parent component can then pass state data to the child component via props. This makes it easier to synchronize and share state data across all components of the application.
9. Composition & Inheritance
React recommends using compositing to reuse code. Props and combinations give you a flexible way to customize the look and behavior of components in a clear and secure way.
Note: Components can accept any props, including basic data types, React elements, and functions.
2. React Philosophy
One of the best parts of React is that it gets us thinking about how to build an application.
For example, suppose we have a design and an API that returns data:
Step 1: Divide your designed UI into component levels
Box each component, including its children, with appropriate names on the design. Component partitioning principle – Single function principle: a component is responsible for only one function.
Step 2: Create a static version of React
Having identified the component hierarchy, you can write the corresponding application. It is best to keep the processes of rendering the UI and adding interactions separate.
Start by rendering a static UI with an existing data model that contains no interaction.
Step 3: Determine the minimum and complete representation of UI state
Find the minimum set of states your application needs, without duplication or redundancy. That is to say, under the premise of realizing the function, the number of variables should be set as minimum as possible.
For example, the sample application has the following data:
- Contains the original list of all products
- The search term entered by the user
- Check box whether the value is selected
- A list of products filtered by search
How to get the minimum representation of check state? Ask yourself three questions:
- Is this data passed by the parent component via props? If so, it should not be state.
- Has the data remained the same over time? If so, it should not be state either.
- Can you calculate the value of this data based on other states or props? If it is, it’s not state.
After checking, the ones belonging to state in the previous example are:
- The search term entered by the user
- Check box whether the value is selected
Step 4: Determine where state is placed — which component should have a state
The data flow in React is one-way and flows up and down the component hierarchy.
For each state in the application:
- Find all components rendered according to this state.
- Find their common owner components (above all components that require this state at the component level).
- The co-owner component or a higher level component should have this state.
- If you can’t find a good place to store the state, you can simply create a new component to store the state and place the new component higher than the co-owner component.
Step 5: Add the reverse data flow
Child components pass values to parent components.
No matter what framework you use, think about how to divide components and how to set variables before you start writing code.
React 16 new features
๐คก React 16 Before the render method had to return a single element, it now supports returning arrays and strings.
class Example extends React.Component {
constructor(props) {
super(props);
}
render() {
return "ssss"; }}Copy the code
๐คก React 16 Before React 16, components blocked the entire application rendering if they failed at runtime. Now there is a new error handling mechanism: By default, when an error is thrown in a component, the component is unloaded from the component tree, preventing the entire application from crashing. React 16 also provides a more user-friendly way of handling errors — Error Boundaries, which are components that can catch and elegantly handle the errors of child components. The elegant process can be to print error logs, display error messages, and so on, which is obviously friendlier than simply uninstalling the component.
The component that defines componentDidCatch(error, info) becomes an error bound:
import React from "react";
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false}; }componentDidCatch(error, info) {
this.setState({
hasError: true});console.log(error, info);
}
render() {
if (this.state.hasError) {
return <h1>OOPS, mistake!</h1>;
}
return this.props.children; }}export default ErrorBoundary;
Copy the code
Using ErrorBoundary:
<ErrorBoundary>
<Example></Example>
</ErrorBoundary>
Copy the code
If the internal component is abnormal, the error will be captured by the ErrorBoundary and a prompt will be displayed on the interface.
The ๐คก Portals feature: Allows you to render a component to a DOM node outside the current component tree. [Teleport is similar to Vue]
ReactDOM.createPortal(child, container);
// Child is a React element/element array/string that can be rendered
// Container is the DOM node to which the child is mounted
Copy the code
For example, create a Modal component:
import React from "react";
import ReactDOM from "react-dom";
class Modal extends React.Component {
constructor(props) {
super(props);
this.container = document.createElement("div");
document.body.appendChild(this.container);
}
conponentWillUnmount() {
document.body.removeChild(this.container);
}
render() {
return ReactDOM.createPortal(<div>I am a Modal</div>.this.container); }}export default Modal;
Copy the code
This makes it the last child of the body no matter where the component is invoked.
๐คก React Hooks: When using Class components, there are a lot of business logic such as all kinds of interface requests need to be put in componentDidMount and componentDidUpdate and other life cycle functions, will make the components become particularly complex and difficult to maintain, and this problem in Class also need special attention; Function components, while avoiding this problem, have no lifecycle, etc.
With Hooks in place, various features of React can be used in functional components.
Hooks are essentially special functions, the common ones being:
๐ฃ useState: useState
const [state, setState] = useState(initState);
// For example
import React, { useState } from "react";
function App() {
const [state, setState] = useState("Hah");
// Whatever u need can be renamed by struct assignment
return (
<div>
<h1>{state}</h1>
</div>
);
}
export default App;
Copy the code
Here, the useState method is asynchronous, like the same method as the component. But it does not merge multiple states.
๐ฃ useRef: useRef
import React, { useRef } from "react";
function App() {
let el = useRef();
return (
<div>
<h1 ref={el}>{state}</h1>
</div>
);
// The DOM node can be obtained from el.current
}
export default App;
Copy the code
๐ฃ useEffect: Handles side effects such as network requests, DOM operations, etc. Equivalent to componentDidMount and componentDidUpdate, etc.
Here’s an example:
import React, { useState, useEffect } from "react";
function Course() {
const [name, setName] = useState("React");
useEffect(() = > {
console.log("Component mount or update");
return () = > {
console.log("Clean up some stuff before the update.");
};
}, [name]);
return (
<div>
<select
value={name}
onChange={({ target}) = > {
setName(target.value);
}}
>
<option value="React">React</option>
<option value="Vue">Vue</option>
<option value="JQuery">JQuery</option>
</select>
</div>
);
}
export default Course;
Copy the code
As you can see, useEffect takes two arguments, the first a function and the second an array, where the first function returns a function and the second array represents dependent arguments. When a dependency parameter changes, the callback function is executed. The entire component lifecycle process: component mounting โ Performing side effects (callback function) โ component updating โ performing cleaning functions (return function) โ Performing side effects (callback function) โ Preparing component for uninstallation โ Performing cleaning functions (return function) โ Component uninstallation.
If you simply want to perform certain operations in a particular lifecycle, you can do this by passing different parameters:
- Only in the
componentDidMount
Execute, you can set the dependent parameters to an empty array so that the side effect is not performed during updates. - Only in the
componentWillUnmount
Execute, also setting the dependency parameters to an empty array, and the return function for that side effect will be executed before unloading. - Only in the
componentDidUpdate
Execution, need update or mount, testing data and the initial values are consistent, if the current data is consistent with the initial data that mount the stage, on the safe side, of course, compared with the previous value, if the current reliance on data dependence and the last data, shows the component hasn’t been updated. This situation calls for helpuseRef
The reason is that if a REF is bound to data, the ref will not be automatically updated when the data is updated, so that the value of the data before the update can be obtained.
โ ๏ธ Hooks can only be called in functional components and custom Hooks, not in normal functions or class components.
โ ๏ธ can only call Hooks at the first level of the function.
Custom Hooks: You can customize logic that needs to be used repeatedly as Hooks, which must begin with use. I’m not going to do any examples here.
4. Understand components in depth
1, the state
Variables that we use in a component that are not related to rendering should be defined as general properties of the component and should not be placed in state. That is, anything that is not used in render should not be used in state.
Note:
- State cannot be changed directly as it does not trigger render.
- Updates to state are asynchronous, and React may merge multiple state changes into one update. Vue has the same mechanism, easy to understand. Updates to the props are also asynchronous.
- Updating state is a merging process.
React recommends treating state as an immutable object, such as using concat, Slice, filter, etc. to return a new array when there is an array in state, rather than using push, POP, Shift, splice, etc. to modify the array directly. If there are objects, use ES6’s object. assign method or Object extension syntax.
// eg
this.setState(preState= > ({ arr: preState.arr.slice(1.3)}))// preState is the old state
Copy the code
2. The component communicates with the server
- Component mount phase communication:
componentDidMount
Hook, officially recommended โ๏ธ
componentDidMount(){
let that = this
fetch('/getXXX').then(funtion(response){
that.setState({
data: response.data
})
})
}
Copy the code
The componentWillMount hook is called before the component is mounted and can also fetch data from the server. If rendered on the server, the componentWillMount hook is called twice, and the componentDidMount hook is called only once. So recommend componentDidMount hook.
- Component update phase communication:
componentWillReceiveProps(nextProps)
hook
3. Communication between components
- Parent and child component communication: props
Parent: props property, child parent: callback
// Call methods of the parent component via props
this.props.handleClick(xxx)
// In the parent component
<Child handleClick={this.handleClick}></Child>
Copy the code
- Sibling communication:
State of ascension
Store shared state in the nearest common parent, the core being props - Context: When the component hierarchy is too deep, it can be cumbersome to bridge functions. React provides a Context so that any child component at any level can access the states and methods in the parent component. Create context: Add a new context to the component that provides it
getChildContext
Method, which returns the Context object, and then thechildContextTypes
Property defines the type information for the properties of the context object.
// The parent component is Father
getChildContext(){
return { handleClick: this.handleClick }
}
// ...
Father.childContextTypes = {
handleClick: PropTypes.func
}
// Child components are accessed through context
this.context.handleClick()
// ...
Child.contextTypes = {
handleClick: PropTypes.func
}
Copy the code
- When a project is complex, state management libraries such as Redux can be introduced.
Special ref — gets a DOM element or component
Use ref on DOM:
this.textInput.focus()
/ / in the render
<input type="text" ref={ (input) = > { this.textInput = input }}/>
// input represents the input element
Copy the code
Use ref on components: [class components only]
this.inputInstance.handleChange() // Call the handleChange method of the inputInstance component instance obtained by ref
/ / in the render
<Child ref={ (input) = > { this.inputInstance = input }}/>
// Input represents the component instance
Copy the code
Virtual DOM and performance optimization
1. Virtual DOM — JS objects
There is a principle in front-end performance optimization that minimizes DOM manipulation, and the virtual DOM embodies this principle.
DIFF algorithm: Compared with the old and new virtual DOM, time complexity O(n).
Assumptions:
(1) If two elements have different types, they will generate two different trees.
(2) Set the key attribute for the element in the list, and use the key to identify whether the corresponding element has changed in the render process for many times.
To be specific:
- When the root node is of a different type, the child node is not compared and the real DOM is generated directly from the new virtual DOM.
- The root node is the same DOM type, keeping the root node and updating the changed root node attributes;
- The root node is the same component type, and the corresponding component instance is not destroyed, but only updated;
- After comparing root nodes, React recursively compares child nodes using the same principle.
- React provides a key property for lists to reuse.
2. Performance optimization
- Avoid unnecessary component rendering and use it wisely
shouldComponentUpdate
A hook that returns true or false depending on the business logic; - Use the key;
- React Developer Tools for Chrome
- According to — did you update the plugin
HOC — Abstraction and reuse of component logic
— HighOrderComponent
1. Basic concepts
Higher-order function: a function that takes a function as an argument and returns a function. Similarly, a higher-order component is a component that takes the React component as an argument and returns a new React component.
How is it different from the parent component? Higher-order components emphasize logical abstraction. A higher-order component is a function, which is concerned with logic; A parent component is a component that is primarily concerned with the UI/DOM. If the logic is directly related to the DOM, then that part of the logic should be implemented in the parent component. If the logic is not directly related to the DOM, this part of the logic is suitable for higher-level component abstractions, such as data validation, request sending, and so on.
For example, let’s write a MyComp component to fetch data from localStorage and display:
class MyComp extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
let data = localStorage.getItem("data");
this.setState({ data });
}
render() {
return <div>{this.state.data}</div>; }}Copy the code
If other components have this logic, try to reuse it:
// Higher-order components
function HocComp(OtherComp) {
return class extends React.Component {
componentWillMount() {
let data = localStorage.getItem("data");
this.setState({ data });
}
render() {
return <OtherComp data={this.state.data} {. this.props} / >; }}; }class MyComp extends React.Component {
render() {
return <div>{this.props.data}</div>; }}const MycompWithOther = HocComp(MyComp);
Copy the code
You can see the main function of higher-order components: encapsulating and separating the general logic of components so that it can be reused better in components — decorator design patterns [๐ฉ : See design patterns later].
2. Application scenarios
1) Manipulation props
The previous example
2) Access the component instance through ref
function withRef(WrappedComp) {
return class extends React.Component {
constructor(props) {
super(props);
this.someMethod = this.someMethod.bind(this);
}
// This saves a reference to the WrappedComp instance
someMethod() {
this.instance.methodOfWrappedComp();
}
render() {
return (
<WrappedComp
ref={(instance)= >{ this.instance = instance; }} {... this.props} />); }}; }Copy the code
3) Component status is improved
For example, higher-order components are used to uniformly promote the state that the controlled components need to maintain themselves into higher-order components.
4) Wrap components with other elements
Such as adding layouts or changing styles:
function withRedBg(WrappedComp) {
return class extends React.Component {
render() {
return (
<div style={{ backgroundColor: "red}} ">
<WrappedComp {. this.props} / >
</div>); }}; }Copy the code
3. Parameter transfer
Higher-order components can accept other parameters besides components as parameters. Such as:
// Higher-order components
function HocComp(OtherComp, key) {
return class extends React.Component {
componentWillMount() {
let data = localStorage.getItem(key);
this.setState({ data });
}
render() {
return <OtherComp data={this.state.data} {. this.props} / >; }}; }class MyComp extends React.Component {
render() {
return <div>{this.props.data}</div>; }}const MycompWithOther = HocComp(MyComp, "data");
/ / or
const MycompWithOther = HocComp(MyComp, "username");
Copy the code
4, inheritance to achieve higher-order components
Higher-order components implemented by inheritance are often used for render hijacking. For example, allow component rendering while the user is logged in; Otherwise render an empty component:
function withAuth(WrappedComp) {
return class extends WrappedComp {
render() {
if (this.props.isLogin) {
return super.render();
} else {
return null; }}}; }Copy the code
7. Router and Redux for project practice
React Router
The React Router contains three libraries: react-Router, react-router-dom, and react-router-native.
- The react-router provides basic routing functions. You can install the React-router-DOM (in the browser) or react-router-native (in the react-native) based on the application environment.
- Both react-router-DOM and react-router-native depend on the React-router, so the react-router is automatically installed during installation.
Install react-router-dom in your Web application:
npm install react-router-dom
Copy the code
React Router Uses the Router and Route components to implement the routing function. A Router can be defined as a Router. Only one Router instance is required in an application. All Route configuration components are defined as sub-components of the Router. 5. Similar to VueRouer
In Web applications, routing is generally divided into:
BrowserRouter
: H5-based history API,HashRouter
Based on the hash:
Route is a component used to configure routing information in the React Router.
import { Route } from 'react-router'
<Route path='/' /> // path matches the path, after which a match object is created as a property in the props to be passed to the rendered component
<Route path='/' component={Home} /> // Render the Home component when matched
// Can also be written as
<Route path='/' render={
(props) = > {
<Home {. props} / >
}
} />
Copy the code
If you only want the first Route to be rendered, you can use Switch:
import {
BrowserRouter as Router, // Notice here
Switch,
Route,
Link
} from "react-router-dom";
// For example, home navigation, exact match
<Router>
<Switch>
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
<Route path='/user' component={User} />
</Switch>
</Router>
// Without Switch, the /about/user path will match the above three routes and will be rendered
Copy the code
The Link component defines how the page is routed when clicked:
<button><Link to='/login'>The login</Link></button>
// To can also be an object
<Link to={{
pathname: '/login',
state: {isLogin : false}
}} />
Copy the code
Redirect components are used for page redirection:
<Redirect to = {xxx}/>
Copy the code
Get routing information in non-routing components: withRouter and Router Hooks.
WithRouter acts a bit like connect in Redux. You pass the component to get routing information to The withRouter. The withRouter passes routing information to the component and returns a new component that can be invoked elsewhere.
import React from "react";
import { withRouter } from "react-router-dom";
function backBtn(props) {
let { history } = props;
return (
<button
onClick={()= >{ history.goBack(); }} > Return to previous page</button>
);
}
backBtn = withRouter(backBtn);
export default backBtn;
Copy the code
In addition to using withRouter to get routing information for non-routed components, Router Hooks have been added to Router5.x, using the same rules as other Hooks in React.
1) useHistory: Calling this Hook returns the history object
2) useLocation: Calling this Hook returns the location object
3) useRouteMatch: Calling this Hook returns a match object
4) useParams: Calling this Hook returns params in the match object, which is the argument passed by path
Basic use of Redux – state manager, similar to Vuex
Let’s say we have a data object for a TODO item:
{
todoList: [{
text: 'eat'.finished: false}, {text: 'sleep'.finished: false}, {text: 'Beat the beans'.finished: false},].visibilityFilter: 'SHOW_FINISHED'
}
Copy the code
If we need to modify the data, we must send an action:
{ type: 'ADD_TODO'.text: 'movement' }
Copy the code
Type indicates the type of action. This is the field that the action must contain. The rest is undefined. How do you parse the action? Redux uses reducer to resolve actions. Reducer is a normal JS function that receives actions as parameters and returns a new application state.
function todoApp(state = {}, action) {
switch (action.type) {
case "ADD_TODO":
// return new state
case "XXXX":
// return new state
default:
returnstate; }}Copy the code
These are the basic concepts of Redux: Store [data container], state [data object], Action [modify command], reducer.
Redux applications need to follow three principles:
- Unique data source: Only one global state object is maintained and stored in Redux’s store
- Keep the application state read-only: The state cannot be changed directly, but rather based on action
- State changes are accomplished by pure functions: Action indicates the intention to modify the state, and reducer must be a pure function
PS: A pure function is a function that always has the same output for the same input without side effects, such as modifying external objects or output to I/O devices.
1) Action: distributed through the Store dispatch method
// action creater, return action
function addTodo(text) {
return {
type: "ADD_TODO",
text,
};
}
Copy the code
Reducer: Describe what happened to the application and respond according to the actions
// reducer
function todoApp(state = {}, action) {
switch (action.type) {
case "ADD_TODO":
return {
...state,
todoList: [
...state.todoList,
{
text: action.text,
finished: false,}]};default:
returnstate; }}Copy the code
3) Store:
- Save the state
- Access the state via getState()
- Send status update actions through Dispatch (Action)
- Register a listener function with subscribe(listener) to listen for state changes
import { createStore } from 'redux'
function todoApp(){}
const store = createStore(todoApp, initState)
// Get the status
const state = store.getState()
/ / send the action
store.dispatch(addTodo('eat'))
// Register the listener function
let listener = store.subscribe(() = >{
console.log(store.getState()) // Get the latest status when updating the status
})
// Unsubscribe and call the function returned by store. Subscribe
listener()
Copy the code
Redux data flow process:
(1) Call store.dispatch(Action). An action is an object that describes what happened. Store.dispatch (Action) can be called from anywhere in the application, including components, XHR callbacks, timers.
(2) Call the reducer function for Redux’s store. The store passes two parameters to the Reducer: the status of the current application and the action. The Reducer must be a pure function whose sole responsibility is to calculate the state of the next application.
(3) The root Reducer will combine the return results of multiple sub-reducer into the final application state. The build form of the root Reducer is entirely up to the user. Redux provides combineReducers that make it easy to combine multiple split reducers together, but you can do without it altogether. When combineReducers is used, actions are passed to each reducer, and the results after reducer processing are merged into the final application state.
(4) The store of Redux saves the complete application state returned by the root Reducer. At this point, the application status is updated. If the UI needs to be updated based on application state, then this is the time to update the UI. For React applications, you can call the component’s setState method at this point to update the UI based on the new application state.
Using the story:
npm install react-redux
Copy the code
Components can be divided into container components and presentation components, depending on intent:
- Container components: Responsible for logic
- Presentation component: Responsible for the UI
React-redux provides a connect function that connects the React component to redux’s Store to generate a container component responsible for data management and business logic:
import { connect } from "react-redux";
// There is a component TodoList
const VisibleTodoList = connect()(TodoList); // Create a container component
// Pass two parameters to synchronize the container component's state changes
const VisibleTodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList);
// mapStateToProps and mapDispatchToProps are both functions
Copy the code
React-redux provides a Provider component:
// Indicate the code
class Provider extends React.Component {
getChildContext() {
return { store: this.props.store };
}
render() {
return this.props.children;
}
}
Provider.childContextTypes = {
store: React.PropTypes.object,
};
// Save store to context
Copy the code
The Provider component passes store to the child component through the context, so the Provider component is typically used as the root component:
import { createStore } from "redux";
import { Provider } from "react-redux";
render(
<Provider>
<App />
</Provider>.document.getElementById("root"));Copy the code
React + Redux
1) How to organize the project structure?
- Files of the same type are organized together according to types: Components, containers, Actions, etc
- According to page function: a page function corresponds to a folder, including Components, Action, etc
- Ducks:github.com/erikras/duc… The application state is used as the basis for module division
2) Design State: Design state like a database
- The state of the entire application is divided into several sub-states according to the domain. Duplicate data cannot be stored between the sub-states
- State stores data as key-value pairs, indexed by the key or ID of the record, and other fields in the record depend on the index
- State cannot hold data that can be computed from existing fields in state, that is, fields in state do not depend on each other
Eight, summary
React has higher requirements for JavaScript basics, such as this, higher-order functions, and classes. React also has a higher level of abstraction. Higher-order components, Redux middleware, and so on, each of which is worth digging into.
Anyway, I finally started to learn React. It is true that “frameworks are interlinked”. My experience in using Vue helped me understand React to a large extent. In the future, I plan to write a small demo to increase my proficiency in React and gradually understand the fundamental things. ๐