Updated createAnimatedComponent to account for async rendering
Reviewed By: sahrens Differential Revision: D6149113 fbshipit-source-id: f28b597c1fe9280ca990fe72efc7b841665de957
This commit is contained in:
parent
01b941927c
commit
870f540336
|
@ -20,6 +20,7 @@ const ViewStylePropTypes = require('ViewStylePropTypes');
|
|||
function createAnimatedComponent(Component: any): any {
|
||||
class AnimatedComponent extends React.Component<Object> {
|
||||
_component: any;
|
||||
_invokeAnimatedPropsCallbackOnMount: boolean = false;
|
||||
_prevComponent: any;
|
||||
_propsAnimated: AnimatedProps;
|
||||
_eventDetachers: Array<Function> = [];
|
||||
|
@ -46,6 +47,11 @@ function createAnimatedComponent(Component: any): any {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this._invokeAnimatedPropsCallbackOnMount) {
|
||||
this._invokeAnimatedPropsCallbackOnMount = false;
|
||||
this._animatedPropsCallback();
|
||||
}
|
||||
|
||||
this._propsAnimated.setNativeView(this._component);
|
||||
this._attachNativeEvents();
|
||||
}
|
||||
|
@ -71,37 +77,44 @@ function createAnimatedComponent(Component: any): any {
|
|||
this._eventDetachers = [];
|
||||
}
|
||||
|
||||
// The system is best designed when setNativeProps is implemented. It is
|
||||
// able to avoid re-rendering and directly set the attributes that changed.
|
||||
// However, setNativeProps can only be implemented on leaf native
|
||||
// components. If you want to animate a composite component, you need to
|
||||
// re-render it. In this case, we have a fallback that uses forceUpdate.
|
||||
_animatedPropsCallback = () => {
|
||||
if (this._component == null) {
|
||||
// AnimatedProps is created in will-mount because it's used in render.
|
||||
// But this callback may be invoked before mount in async mode,
|
||||
// In which case we should defer the setNativeProps() call.
|
||||
// React may throw away uncommitted work in async mode,
|
||||
// So a deferred call won't always be invoked.
|
||||
this._invokeAnimatedPropsCallbackOnMount = true;
|
||||
} else if (
|
||||
AnimatedComponent.__skipSetNativeProps_FOR_TESTS_ONLY ||
|
||||
typeof this._component.setNativeProps !== 'function'
|
||||
) {
|
||||
this.forceUpdate();
|
||||
} else if (!this._propsAnimated.__isNative) {
|
||||
this._component.setNativeProps(
|
||||
this._propsAnimated.__getAnimatedValue(),
|
||||
);
|
||||
} else {
|
||||
throw new Error(
|
||||
'Attempting to run JS driven animation on animated ' +
|
||||
'node that has been moved to "native" earlier by starting an ' +
|
||||
'animation with `useNativeDriver: true`',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
_attachProps(nextProps) {
|
||||
const oldPropsAnimated = this._propsAnimated;
|
||||
|
||||
// The system is best designed when setNativeProps is implemented. It is
|
||||
// able to avoid re-rendering and directly set the attributes that
|
||||
// changed. However, setNativeProps can only be implemented on leaf
|
||||
// native components. If you want to animate a composite component, you
|
||||
// need to re-render it. In this case, we have a fallback that uses
|
||||
// forceUpdate.
|
||||
const callback = () => {
|
||||
if (
|
||||
!AnimatedComponent.__skipSetNativeProps_FOR_TESTS_ONLY &&
|
||||
this._component.setNativeProps
|
||||
) {
|
||||
if (!this._propsAnimated.__isNative) {
|
||||
this._component.setNativeProps(
|
||||
this._propsAnimated.__getAnimatedValue(),
|
||||
);
|
||||
} else {
|
||||
throw new Error(
|
||||
'Attempting to run JS driven animation on animated ' +
|
||||
'node that has been moved to "native" earlier by starting an ' +
|
||||
'animation with `useNativeDriver: true`',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.forceUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
this._propsAnimated = new AnimatedProps(nextProps, callback);
|
||||
this._propsAnimated = new AnimatedProps(
|
||||
nextProps,
|
||||
this._animatedPropsCallback,
|
||||
);
|
||||
|
||||
// When you call detach, it removes the element from the parent list
|
||||
// of children. If it goes to 0, then the parent also detaches itself
|
||||
|
@ -157,13 +170,7 @@ function createAnimatedComponent(Component: any): any {
|
|||
}
|
||||
}
|
||||
|
||||
// ReactNative `View.propTypes` have been deprecated in favor of
|
||||
// `ViewPropTypes`. In their place a temporary getter has been added with a
|
||||
// deprecated warning message. Avoid triggering that warning here by using
|
||||
// temporary workaround, __propTypesSecretDontUseThesePlease.
|
||||
// TODO (bvaughn) Revert this particular change any time after April 1
|
||||
const propTypes =
|
||||
Component.__propTypesSecretDontUseThesePlease || Component.propTypes;
|
||||
const propTypes = Component.propTypes;
|
||||
|
||||
AnimatedComponent.propTypes = {
|
||||
style: function(props, propName, componentName) {
|
||||
|
|
Loading…
Reference in New Issue