About a year ago, the React team released React 16.0. Today, it has been updated to 16.5. There are a lot of exciting features (Fiber architecture, new periodic functions, new Content API, Fragment, Error Boundary, Portal, etc.) that are worth following up on. In this paper, in order to
React Update LogFor reference, pick a few important updates that you can use at work and learn from them. All sample code in
react-upgrade-examples, it is better to eat with the article ~ 😆
directory
0. Updates of life cycle functions
1. The new Content API
2. React Strict Mode
3. Portal
4. Refs
5. Fragment
6. Other
7. To summarize
Updates to life cycle functions
With React 16.0, React uses a new core architecture, Fiber, which breaks the update into two phases: Render Parse and Commit Parse introduce getDerivedStateFromProps, getSnapshotBeforeUpdate, and componentDidCatch. At the same time, also will componentWillUpdate, componentWillReceiveProps and componentWillUpdate marked as unsafe.
new
static getDerivedStateFromProps(nextProps, prevState)
getSnapshotBeforeUpdate(prevProps, prevState)
componentDidCatch(error, info)
Mark it as unsafe
componentWillMount(nextProps, nextState)
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
static getDerivedStateFromProps(nextProps, prevState)
GetDerivedStateFromProps (nextProps, prevState) updates the state based on the props passed. One of its major features is that it has no side effects: because it is in the Render Phase, every update will be triggered, so the static method is used in the design of THE API, which has the advantage of simplicity — no instance can be accessed, no DOM object can be accessed through ref, etc., ensuring simplicity and efficiency. It is worth noting that side effects can still be generated by the operations of props. In this case, the operation method of props should be moved to componentDidUpdate to reduce the triggering times.
Ex. :
state = { isLogin: false } static getDerivedStateFromProps(nextProps, prevState) { if(nextProps.isLogin ! == prevState.isLogin){ return { isLogin: nextProps.isLogin } } return null } componentDidUpdate(prevProps, prevState){ if(! prevState.isLogin && prevProps.isLogin) this.handleClose() }Copy the code
But be very careful when using, because it’s not like componentWillReceiveProps, to trigger, only when the parent component to render itself calls setState can be set. The official has provided three checklists. Here are some of them:
- If you change
props
At the same time, there are side effects (such as asynchronous requests for data, animation effects), should be usedcomponentDidUpdate
- If you want to base
props
To compute attributes, you should consider memoization of the results, seememoization - If you want to base
props
Change to reset some state, and you should consider using controlled components
Cooperate with componentDidUpdate periodic function, and getDerivedStateFromProps is to replace componentWillReceiveProps appeared. It will update the state componentWillReceiveProps function division, and action/call props, largely avoided the responsibility is not clear and cause too much rendering, should that affect performance.
getSnapshotBeforeUpdate(prevProps, prevState)
GetSnapshotBeforeUpdate (prevProps, prevState) It gets a snapshot before the component is updated — you can pass the calculated value or information from the DOM to the third parameter of the componentDidUpdate(prevProps, prevState, Snapshot) periodic function, Often used for scroll position. From the official example:
Class ScrollingList extends react.component{constructor(props) {super(props) // Get the dom object this.listref = React.createRef() } getSnapshotBeforeUpdate(prevProps, PrevState) {// If (prevProps. List. length < this.props. List.length) {const list = prevProps this.listRef.current return list.scrollHeight - list.scrollTop } return null } componentDidUpdate(prevProps, prevState, Snapshot) {// If (snapshot! == null) { const list = this.listRef.current list.scrollTop = list.scrollHeight - snapshot } } render() { return <div ref={this.listRef}>{/* ... contents... */}</div> } }Copy the code
componentDidCatch(error, info)
Prior to 16.0, error capture was performed using unstable_handleError, which captured very limited information, or using third-party libraries such as react-error-overlay, which was unoffunoffally supported. In 16.0, the componentDidCatch cycle function was added to allow developers to process Error information independently, such as displaying and reporting errors, etc. Users could create their own Error Boundary to capture errors. Ex. :
·· componentDidCatch(error, info) {// Display fallback UI this.setState({hasError: true}); // You can also log the error to an error reporting service logErrorToMyService(error, info); }...Copy the code
In addition, users can also use third-party error tracking services such as Sentry and Bugsnag to ensure efficient error handling while greatly reducing the cost of error tracking for small and medium-sized projects.
Mark it as unsafecomponentWillMount
,componentWillReceiveProps
,componentWillUpdate
componentWillMount
ComponentWillMount can be used by developers to get first screen data or transaction subscriptions.
To get data quickly, the developers put the first screen request in componentWillMount. The first rendering actually starts when executing componentWillMount. Placing the first screen request on componentWillMount or not does not solve the problem of the first screen rendering of random step data. The official recommendation is to place the first screen in constructor or componentDidMount.
In addition, the event subscription is often used in componentWillMount, and unsubscribe the corresponding event subscription in componentWillUnmount. React does not guarantee that when componentWillMount is called, the same componentWillUnmount will also be called. On the other hand, in the future, when React turns on asynchronous rendering mode, it is very likely that component rendering will be interrupted by other transactions after · is called, resulting in componentWillUnmount not being called. ComponentDidMount does not have this problem. After componentDidMount is called, componentWillUnmount must be called later, and the component will be cleaned up according to the specific code.
ComponentDidMount = componentWillMount ();
componentWillReceiveProps
,componentWillUpdate
ComponentWillReceiveProps is marked as unsafe reasons mentioned above, the main reason is the result of the operation props re – render. Similarly, componentWillUpdate is marked as unsafe for the same reason. In addition, DOM updates can cause re-rendering.
For componentWillReceiveProps upgrade scheme is to use getDerivedStateFromProps and componentDidUpdate instead. For componentWillUpdate upgrade scheme is to use componentDidUpdate instead. If a large number of calculations are involved, you can complete the calculations in getSnapshotBeforeUpdate and then update them once at componentDidUpdate.
The use of frame-level apis to restrict or even restrict developers from writing more maintainable Javascript code minimizes anti-pattern development.
New Context API
Before React 16.3, the Context API was officially deprecated because the old Context API, as an experimental product, broke the fractal structure of React. If a component’s shouldComponentUpdate returns false, then the Context API is impenetrable. The uncertainty it creates leads to its not being recommended. With the React 16.3 release, the new Context API is a first-class API that can easily penetrate components without side effects.
// Context lets us pass a value deep into the component tree // without explicitly threading it through every component. // Create a context for the current theme (with "light" as the default). const ThemeContext = React.createContext('light') class App extends React.Component { render() { // Use a Provider to pass the current theme to the tree below. // Any component can read it, no matter how deep it is. // In this example, we're passing "dark" as the current value. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ) } } // A component in the middle doesn't have to // pass the theme down explicitly anymore. function Toolbar(props) { return ( <div> <ThemedButton /> </div> ) } function ThemedButton(props) { // Use a Consumer to read the current theme context. // React will find the closest theme Provider above and use its value. // In this example, the current theme is "dark". return ( <ThemeContext.Consumer>{theme => <Button {... props} theme={theme} />}</ThemeContext.Consumer> ) }Copy the code
The process is roughly as follows:
- through
React.createContext
Creating a Context object - On the parent component, use
<ThemeContext.Provider/>
To provide the Provider - Where consumption is needed, use
<ThemeContext.Consumer/>
In the form of function calls{theme => <Button {... props} theme={theme} />}
Get the value of the Context object.
The Context API with the story
In terms of state management, the new Context API can completely replace part of the Redux application.
const initialState = { theme: 'dark', color: 'blue', } const GlobalStore = React.createContext() class GlobalStoreProvider extends React.Component { render() { return ( <GlobalStore.Provider value={{ ... initialState }}>{this.props.children}</GlobalStore.Provider> ) } } class App extends React.Component { render() { return ( <GlobalStoreProvider> <GlobalStore.Consumer> {context => ( <div> <div>{context.theme}</div> <div>{context.color}</div> </div> )} </GlobalStore.Consumer> </GlobalStoreProvider> ) } }Copy the code
The ability to penetrate components brought about by the new Context API is useful in scenarios where global state sharing is required, where state can be managed without entering additional dependencies and the code is clean.
React Strict Mode
React StrictMode detects potential problems in applications during development and reminds developers to solve problems, ensuring application robustness. It can mainly detect four problems:
- Identify life cycle functions that are flagged as unsafe
- Warn against deprecated apis
- Detect some methods that produce side effects
- Check whether the old Context API is used
React StrictMode is easy to use, just wrap a layer around the components that need to be checked React StrictMode
class App extends React.Component {
render() {
return (
<div>
<React.StrictMode>
<ComponentA />
</React.StrictMode>
</div>
)
}
}
Copy the code
If an error occurs, print a specific error message on the console:
Portal
The createPortal method provided by the ReactDOM allows components to be rendered to other DOM nodes. This is useful for large applications or for rendering independent of the application itself. The function signature is reactdom.createPortal (child, container), and the child argument is any renderable React Component, such as Element, sting, fragment, etc. Container is the DOM node to be mounted.
Take a simple Modal example, see the code for Portal Modal:
import React from 'react' import ReactDOM from 'react-dom' const modalRoot = document.querySelector('#modal') export default class Modal extends React.Component { constructor(props) { super(props) this.el = document.createElement('div') } componentDidMount() { modalRoot.appendChild(this.el) } componentWillUnmount() { modalRoot.removeChild(this.el) } handleClose = () => [this.props.onClose && this.props.onClose()] render() { const { visible } = this.props if (! visible) return null return ReactDOM.createPortal( <div> {this.props.children} <span onClick={this.handleClose}>[x]</span> </div>, this.el ) } }Copy the code
After passing children using props, use reactdom. createPortal to render container on other DOM nodes.
Refs
React uses the Virtual DOM to update views, but at some point we need to manipulate the real DOM, where the ref attribute comes in handy.
React.createRef
React 16 uses React. CreateRef to get the Ref object.
Before React 16 ··· componentDidMount() {// The refs object container the myRef const el = this.refs.myref // you can also using ReactDOM.findDOMNode // const el = ReactDOM.findDOMNode(this.refs.myRef) } render() { return <div // React 16+ constructor(props) {super(props) this.myref = React. CreateRef ()} render() {// React 16+ constructor(props) {// React 16+ constructor(props) { Return <div ref={this.myref} />} ···Copy the code
React.forwardRef
Another new feature is Ref forwarding, which is intended to give the parent component access to the child component’s Ref to manipulate its DOM. ForwardRef receives a function with parameters like props and ref. For a simple example, see Refs:
const TextInput = React.forwardRef((props, ref) => ( <input type="text" placeholder="Hello forwardRef" ref={ref} /> )) const inputRef = React.createRef() class App extends Component { constructor(props) { super(props) this.myRef = React.createRef() } handleSubmit = event => { event.preventDefault() alert('input value is:' + inputRef.current.value) } render() { return ( <form onSubmit={this.handleSubmit}> <TextInput ref={inputRef} /> <button type="submit">Submit</button> </form> ) } }Copy the code
This example uses the React. ForwardRef to pass props and ref to the child component, which can be called directly from the parent component.
Fragment
When add elements to the DOM tree volume, a good practice is to create a document createDocumentFragment, first add elements in bulk to the DocumentFragment, again add DocumentFragment to DOM tree, This reduces the number of DOM operations without creating a new element.
Like DocumentFragment, React also has the concept of Fragment for similar purposes. Before React 16, the react-addons-create-fragment extension was used to create fragments. In React 16, use < react. Fragment>
to create a ‘Fragment’ directly. Such as:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
)
}
Copy the code
This way, we don’t need to wrap a separate layer of useless elements (as with
wrapping), reducing the level of nesting. In addition, there is a concise way to write:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
)
}
Copy the code
other
ReactDOM
的 render
The React Component function can return the React Component as an array
render(){
return [
<ComponentA key='A' />,
<ComponentB key='B' />,
]
}
Copy the code
Remove the built-inreact-with-addons.js
All plug-ins are separate
React-addons -(CSS -)transition-group,react-addons-create-fragment,react-addons-pure-render-mixin, react-Addons-perf, etc Etc., except for part of the built-in, the rest are all independent of a project, pay attention to the use.
conclusion
The React 16.0 ~ 16.5 upgrades give developers a much purer development process. Changes at the API level, architecture changes, and tool classes are all part of the effort to build more maintainable JavaScript applications. Embrace change and go with the flow.
Due to the limited ability of the author, there are omissions in the article, but also hope that readers are generous to give advice. 😀
The above.
Find me on Github.
Reference:
- React Docs
- Update on Async Rendering
- You Probably Don’t Need Derived State
- React V16.3: New lifecycle functions
- React 16: A look inside an API-compatible rewrite of our frontend UI library
- React Fiber Architecture