Default value for the React property
Notifys React of the default properties with a static property called defaultProps
// app.jsx file uses Comp component and passes properties
import React from 'react'
import ReactDOM from 'react-dom'
import Comp from './Comp'
const MOUNT_NODE = document.getElementById('root')
ReactDOM.render(<Comp a={5} b={6} />, MOUNT_NODE)
Copy the code
Function component writing
In terms of presentation, the blending of the properties passed by the parent component and the default properties is complete before the function runs
// com.jsx function component
import React from 'react'
const Comp = props= > {
console.log(props) {a: 5, b: 6, c: 3}}
return (
<div>
a: {props.a}, b: {props.b}, c: {props.c}
</div>)}/* Property default declaration */
Comp.defaultProps = {
a: 1.b: 2.c: 3
}
export default Comp
Copy the code
Class component writing
From a presentation point of view, the properties passed by the parent component are mixed with the default properties before the constructor constructor is run (i.e. the properties are mixed during initialization)
// Comp.jsx class components
import React, {Component} from 'react'
class Comp extends Component {
/* Method 1: Use the static keyword to declare the default property */
static defaultProps = {
a: 1.b: 2.c: 3
}
constructor(props) {
super(props)
console.log(props) {a: 5, b: 6, c: 3}}
}
render() {
return (
<div> a: {this.props.a}, b: {this.props.b}, c: {this.props.c} </div>)}}/* Method 2: declare the default value of the attribute */
// Comp.defaultProps = {
// a: 1,
// b: 2,
// c: 3
// }
export default Comp
Copy the code
Attribute type check —prop-types
Use the static propTypes property on components to tell React how to check types (React has a prop-types package built into it)
It does not affect the execution of the code, only does type checking at compile time during the development phase, and prints warnings on the console about non-compliance with type constraints
// Comp.jsx class components
import React, {Component} from 'react'
import PropTypes from 'prop-types'
class Comp extends Component {
static propTypes = {
a: PropTypes.number.isRequired /* Constraint a attribute is numeric and */ is mandatory
}
render() {
return (
<div>
a: {this.props.a}
</div>)}}export default Comp
Copy the code
It is a weakly typed type checking system compared to TypeScript, and the runtime performance is similar to that of the runtime
A better solution, of course, is to use TypeScript with its strong typing constraints to avoid fewer coding errors
Higher-order component — HOC
HOC:Higher-Order Component
Start with the idea of a higher-order function, pass a component as a parameter, and return a new component with enhanced functionality. We can use the flexibility of JS features to play out a lot of tricks
An 🌰
For example, in one scenario, there are 20 components that need a common function: print the point in time for mounting and unmounting. Instead of using HOC, we need to repeatedly write the hook function for componentDidMount and componentWillUnmount for each of the 20 components
HOC implementation scheme
Using HOC, we simply pull out the public method that prints the log and return a new component that includes logging, as follows:
import React, {Component} from 'react'
// In naming, functions that return HOC usually begin with with, indicating the enhanced component
function withLog (Comp) {
return class extends Component {
componentDidMount() {
console.log(`${Comp.name} is Mounted, the time is The ${Date.now()}`)}componentWillUnmount() {
console.log(`${Comp.name} will Unmount, the time is The ${Date.now()}`)}render() {
return <Comp {. this.props} / >}}}export default withLog
Copy the code
In future use, we only need to call this function for each component that needs to print logs to meet the requirements of the log printing function. The example is as follows:
import React, {Component} from 'react'
import withLog from './HOC/withLog'
class AComp extends Component {
// do somthing...
}
const ALogComp = withLog(AComp)
export default ALogComp
Copy the code
Change the way of thinking
Extend the functionality by implementing a new class that inherits from the React.ponent class
import React, {Component} from 'react'
class LogComponent extends Component {
componentDidMount() {
// But we don't know which component is mounted
console.log(`Component is Mounted, the time is The ${Date.now()}`)}}export default LogComponent
Copy the code
The next 20 components only need to inherit this class to meet the requirement of printing logs… (Of course, this is just my personal thought of a way to cheat, not recommended)
HOC points of attention
-
The return higher-order component is itself a function, so the parameters passed by the function can be handled by yourself, as well as the internal processing logic
-
Do not use higher-order components in render functions or function components, otherwise they will be recreated each time, wasting performance and losing the previous state
import React, {Component} from 'react' import Comp from './components/Comp' import withLog from './HOC/withLog' const LogComp = withLog(Comp) // Write here, ALogComp is reused class AComp extends Component { // do somthing... render() { // Write here, ALogComp will be destroyed and re-created each time // const LogComp = withLog(Comp) return <LogComp />}}export default AComp Copy the code
-
Do not change incoming components within higher-order components, such as changing lifecycle methods on their prototype chain
import React, {Component} from 'react' function withLog (Comp) { // Do not override properties and methods passed to components in this way // Comp.prototype.componentDidMount = function() { // // do something... // } return class extends Component { render() { return <Comp {. this.props} / >}}}export default withLog Copy the code
-
Issues with REF passing (problems with encapsulating high order component REF references)
Just look at the following, the end of this article
Ref (Reference)
In some cases, we may need to call a method on a DOM element, or we may want to use a method directly from a custom component
Scene 1: We click a button to focus the input field
-
In native JS, we just need to do this:
const inpDom = document.querySelector('input') // Assume that the page has only one input // Then call the focus method to implement the focus inpDom.focus() Copy the code
-
React also gives us a way to manipulate the DOM directly, similar to Vue (this.$refs.xx)
import React, {Component} from 'react' class Comp extends Component { handleClick = () = > { // this.refs.txt 就是 input this.refs.txt.focus() } render() { return ( <div>{/* use the 'TXT' string directly. Use the React. CreateRef method to create */}<input type="text" ref="txt" /> <button onClick={this.handleClick}>Input field focus</button> </div>)}}export default Comp Copy the code
Scenario 2: The component Dog has a method called bark, and I need to call the method inside the Dog at the location that references the Dog component
import React, {Component} from 'react'
class Dog extends Component {
bark() {
console.log('Dog is barking... ')}render() {
return <div> Dog Component </div>}}class Comp extends Component {
handleClick = () = > {
// this.refs.compDog is the instance object currently generated using the Dog component
this.refs.compDog.bark() // Call the bark method on the prototype chain
}
render() {
return (
<div>
<Dog ref="compDog" />
<button onClick={this.handleClick}>Call the method of the child component</button>
</div>)}}export default Comp
Copy the code
Ref use summary:
- Ref acts on the React built-in Html component (e.g.
<h1>
/<div>
Etc.), and the result will be the real DOM object - Ref acts on a class component, and the result will be an instance object of the class
- Ref (ref (ref (ref (ref (ref (ref (ref))) cannot apply to function components.
The ref attribute recommends passing an object or function
object
(byReact.createRef()
Create or manually create{ current: null }
)
import React, {Component, createRef} from 'react'
class Comp extends Component {
constructor (props) {
super(props)
this.txt = createRef() // Return an object stored in the current property
// In this case, the current property is null
// After the initial render, the current property is assigned to an instance of a DOM element or class
/* { current: xxx } */
// It is also possible to create an object manually, as long as it contains the current property
// This structure is designed to improve efficiency by keeping the reference to this.txt unchanged
/* this.txt = {current: null
}
handleClick = () = > {
// There is no DOM object in this.refs
this.txt.current.focus()
}
render() {
return (
<div>
<input type="text" ref={this.txt} />
<button onClick={this.handleClick}>Call the method of the child component</button>
</div>)}}export default Comp
Copy the code
function
As shown in the following example, we pass a function to ref that takes a DOM element or an instance of a class (object K) that follows the rules in the above summary, and the call time of the function:
componentDidMount
(The ref object cannot be used in previous lifecycle functions)- if
ref
The old function is replaced by the new function. The old function and the new function are called respectively at the point in timecomponentDidUpdate
Before.The old function call passes null, the new function passes the object K
- if
ref
This function is also called when the component is unloaded. (The passed function uses a reference, as shown belowGetRef method
)
import React, {Component} from 'react'
class Comp extends Component {
handleClick = () = > {
this.txt.focus() // The function is assigned directly to the this.txt property
}
/* This function reference remains unchanged and is executed only during the mount and unload phases
getRef = el= > {
console.log('getRef is called ', el)
this.stableRef = el
}
render() {
return (
<div>{/* this is where the arrow function is written, each time it is a new function */}<input type="text" ref={el= >{console.log(' arrow function ref reference called ', el) this.txt = el // Save ref reference}} /><input type="text" ref={this.getRef} />
<button onClick={this.handleClick}>Call the method of the child component</button>
</div>)}}export default Comp
Copy the code
Forward (refforwardRef
)
To solve the problem, here’s an example of an App component that wants to retrieve the object K inside the function component Comp (such as the div element in the example) :
import React, {Component} from 'react'
function Comp (props) {
return <div>Component Comp</div>
}
class App extends Component {
render() {
return (
<div>{/* function components are not allowed to use ref, give the ref property, the console will report a warning */}<Comp />
</div>)}}export default App
Copy the code
Therefore, we need to create a new component using the React. ForwordRef function to help us forward the ref, which will then be passed to the function component as its second argument
import React, {Component, createRef, forwardRef} from 'react'
function Comp (props, ref) {
return <div ref={ref}>Component Comp</div>
}
// Return a new component passed as the second argument to the function component Comp
const RefComp = forwardRef(Comp)
// The ref attribute received by the new component is only passed to the component, not referred to itself
class App extends Component {
compRef = createRef() // This.pref.current stores the div DOM element
render() {
return (
<div>
<RefComp ref={this.compRef} />
</div>)}}export default App
Copy the code
Note:
-
The argument to the React. ForwardRef function must be a function component, not a class component. And the function component must take the second argument to receive the REF, otherwise a warning will be sent
-
If a class component is expected to refer directly to an element in the class component Comp in the App component, it can be passed with a simple attribute
import React, {Component, createRef} from 'react' class Comp extends Component { render() { return <div ref={this.props.reference}>Component Comp</div>}}class App extends Component { compRef = createRef() // This.pref.current stores the div DOM element render() { return ( <div>{/* customize a simple property pass ref object */}<Comp reference={this.compRef} /> </div>)}}export default App Copy the code
-
In the case of a higher-order component, since the return is directly a new class component, the ref object points to the HOC wrapper when we use the REF attribute on it, which is obviously not what we expect. So you need to encapsulate the ref forwarding processing in the HOC (take the previous withLog example)
// withLog.jsx [HOC] import React, {Component, createRef, forwardRef} from 'react' export default function withLog(Comp) { class LogWrapper extends Component { componentDidMount() { console.log(`${Comp.name} is Mounted, the time is The ${Date.now()}`)}ForwardRef = ref */ render() { const{forwardRef, ... rest} =this.props return <Comp ref={forwardRef} {. rest} / >}}return forwardRef((props, ref) = > { return <LogWrapper {. props} forwardRef={ref} />})}// This way, we don't need to worry about ref references when we use the high order withLog component // Attribute names that are passed from HOC to REF should be written in a special way to avoid duplication // main.jsx import React, {Component, createRef} from 'react' import ReactDOM from 'react-dom' import CompA from './components/CompA' import withLog from './hoc/withLog' const LogCompA = withLog(CompA) class App extends Component { compRef = createRef() render() { return <LogCompA ref={this.compRef} />}}export default App Copy the code
These are the React default properties, high order component use and packaging points to note, ref use and ref forward need to pay attention to related instructions