Use of Animated library

See this article for Animated library usage

Implementation principle:

Now that we have a basic understanding of the various apis commonly used by RN Animated in this article, let’s look at how they were designed. First, programming from the React lifecycle, an animation would look something like this:

getInitialState() {
    return {left: 0};
}

render(){
    return (
        <div style={{left: this.state.left}}>
            <Child />
        </div>
    );
}

onChange(value) {
    this.setState({left: value});
}
Copy the code

Just call onChange with requestAnimationFrame, enter the corresponding value, and the animation simply runs. But it’s not always that simple. What’s the problem?

As we can see, the above animation basically calls setState at the frequency of milliseconds. However, each setState of React will re-call the render method and cut through the child elements for rendering. Even with Dom Diff, it may not be able to handle such a large amount of calculation and UI rendering.

So how do you optimize?

  • Key words:
    • ShouldComponentUpdate
    • (Static container)
    • Element Caching
    • Raw DOM Mutation (native DOM Mutation)
    • ↑↓↓←→←→BA (Secret Book)

ShouldComponentUpdate

ShouldComponentUpdate (ShouldComponentUpdate) is a good way to optimize performance, just need to return false in the sub-component ShouldComponentUpdate, minutes render performance burst table.

However, not all child elements are immutable, and returning false rudely will turn them into a pool of dead water. And components should be independent, child components are likely to be written by others, and the parent element cannot depend on the implementation of the child element.

(Static container)

ShouldCompontUpdate = ShouldCompontUpdate = ShouldCompontUpdate

Ming and Wang no longer have to worry about the animation implementation of the parent element.

A simple <StaticContainer> implementation would look like this:

class StaticContainer extends React.Component { render(){ return this.props.children; } shouldComponentUpdate(nextProps){ return nextProps.shouldUpdate; }} // StaticContainer render() {return (<div style={{left: this.state.left}}> <StaticContainer shouldUpdate={! this.state.isAnimating}> <ExpensiveChild /> </StaticContainer> </div> ); }Copy the code

Element Caching Indicates the cache Element

Another way to optimize rendering of child elements is to cache the render results of child elements into local variables.

render(){
    this._child = this._child || <ExpensiveChild />;
    return (
        <div style={{left:this.state.left}}>
            {this._child}
        </div>
    );
}
Copy the code

After caching, React no longer renders child elements through DOM Diff every time it sets state.

All of the above methods have drawbacks, namely, conditional competition. When the animation is in progress, the child element happens to get a new state, and the animation ignores this update, which eventually leads to inconsistent state, or the child element flashes at the end of the animation, all of which can affect the user’s operation.

Raw DOM Mutation Native DOM operation

In fact, we only want to change the element’s left value. We don’t want any rerendering, DOM DIFF, etc.

“React, I know what I’m doing. Go fuck yourself.”

Wouldn’t it be easier if we jumped out of the lifecycle and just went to the element and changed it?

Easy to understand, powerful performance, right? !

However, the disadvantages are obvious, such as the animation error after the component is unmounted.

Uncaught Exception: Cannot call ‘style’ of null

This method also does not avoid conditional contention – it is possible that setState will be changed and left will return to its original value.

In addition, we use React because we don’t want to care about dom operations. Instead, React manages them.

↑↓↓←→←→BA (Secret Book)

All this nagging, no one, no one, what is the truth?

We want the high performance of native DOM operations with the sophisticated lifecycle management of React. How do we combine the advantages of both? The answer is Data Binding

render(){ return( <Animated.div style={{left: this.state.left}}> <ExpensiveChild /> </Animated.div> ); } getInitialState(){ return {left: new Animated.Value(0)}; } onUpdate(value){this.state.left.setvalue (value); // not setState}Copy the code

First, you need to implement a class with data-binding capabilities like Animated.Value, which provides interfaces like setValueonChange. Second, because the native component does not recognize Value, Animated elements need to be wrapped around Animated to handle data changes and DOM manipulation internally.

A simple animation component is implemented as follows:

Animated.div = class extends React.Component{ componentWillUnmount() { nextProps.style.left.removeAllListeners(); }, / / componentWillMount need to complete the same operations as the componentWillReceiveProps, Here is a little componentWillReceiveProps (nextProps) {nextProps. Style. Left. RemoveAllListeners (); nextProps.style.left.onChange(value => { React.findDOMNode(this).style.left = value + 'px'; }); _props = React. Addons. Update (nextProps, {style:{left:{$set: nextProps.style.left.getValue()}}} ); }, render() { return <div ... {this._props} />; }}Copy the code

The code is short and does the following:

  1. Iterate over the props passed to see if there is an instance of Animated.Value and bind the corresponding DOM operation.
  2. Stop listening for data binding events every time the props changes or components are unmounted, avoiding conditional contention and memory leaks.
  3. Convert the Animated.Value values originally passed in to normal values one by one and pass them to the native React component for rendering.

All in all, by encapsulating an Animated element, changing elements internally through data binding and DOM manipulation, improving memory management and resolving conditional contention issues with React lifecycle, and performing the same as native components, you achieve smooth and efficient animation.

Now, why Animated elements like Image Text should always be Animated by Animated elements?