Skip to content

Commit

Permalink
Make ScrollView StrictMode compatible
Browse files Browse the repository at this point in the history
Converts ScrollView to use constructor instead of UNSAFE_componentWillMount and componentDidUpdate
instead of UNSAFE_componentWillReceiveProps.

Related to facebook#22186
  • Loading branch information
Jyrno42 committed Mar 30, 2019
1 parent af38a0c commit 2550ad8
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 25 deletions.
5 changes: 2 additions & 3 deletions Libraries/Components/ScrollResponder.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,12 +607,11 @@ const ScrollResponderMixin = {
},

/**
* `componentWillMount` is the closest thing to a standard "constructor" for
* React components.
* Constructor for this mixin, call from constructor or from deprecated UNSAFE_componentWillMount
*
* The `keyboardWillShow` is called before input focus.
*/
UNSAFE_componentWillMount: function() {
scrollResponderMixinConstructor: function() {
const {keyboardShouldPersistTaps} = this.props;
warning(
typeof keyboardShouldPersistTaps !== 'boolean',
Expand Down
41 changes: 19 additions & 22 deletions Libraries/Components/ScrollView/ScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,17 @@ class ScrollView extends React.Component<Props, State> {
// $FlowFixMe - dynamically adding properties to a class
(this: any)[key] = ScrollResponder.Mixin[key];
});

this._scrollResponder.scrollResponderMixinConstructor();

this._scrollAnimatedValue = new AnimatedImplementation.Value(
props.contentOffset ? props.contentOffset.y : 0,
);
this._scrollAnimatedValue.setOffset(
props.contentInset ? props.contentInset.top : 0,
);
this._stickyHeaderRefs = new Map();
this._headerLayoutYs = new Map();
}

_scrollAnimatedValue: AnimatedImplementation.Value = new AnimatedImplementation.Value(
Expand All @@ -650,35 +661,21 @@ class ScrollView extends React.Component<Props, State> {
...ScrollResponder.Mixin.scrollResponderMixinGetInitialState(),
};

UNSAFE_componentWillMount() {
this._scrollResponder.UNSAFE_componentWillMount();
this._scrollAnimatedValue = new AnimatedImplementation.Value(
this.props.contentOffset ? this.props.contentOffset.y : 0,
);
this._scrollAnimatedValue.setOffset(
this.props.contentInset ? this.props.contentInset.top : 0,
);
this._stickyHeaderRefs = new Map();
this._headerLayoutYs = new Map();
componentDidMount() {
this._updateAnimatedNodeAttachment();
}

UNSAFE_componentWillReceiveProps(nextProps: Props) {
componentDidUpdate(prevProps: Props) {
const prevContentInsetTop = prevProps.contentInset
? prevProps.contentInset.top
: 0;
const currentContentInsetTop = this.props.contentInset
? this.props.contentInset.top
: 0;
const nextContentInsetTop = nextProps.contentInset
? nextProps.contentInset.top
: 0;
if (currentContentInsetTop !== nextContentInsetTop) {
this._scrollAnimatedValue.setOffset(nextContentInsetTop || 0);
if (prevContentInsetTop !== currentContentInsetTop) {
this._scrollAnimatedValue.setOffset(currentContentInsetTop || 0);
}
}

componentDidMount() {
this._updateAnimatedNodeAttachment();
}

componentDidUpdate() {
this._updateAnimatedNodeAttachment();
}

Expand Down
4 changes: 4 additions & 0 deletions RNTester/js/RNTesterList.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ const APIExamples: Array<RNTesterExample> = [
key: 'ShareExample',
module: require('./ShareExample'),
},
{
key: 'StrictModeExample',
module: require('./StrictModeExample'),
},
{
key: 'TimePickerAndroidExample',
module: require('./TimePickerAndroidExample'),
Expand Down
4 changes: 4 additions & 0 deletions RNTester/js/RNTesterList.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,10 @@ const APIExamples: Array<RNTesterExample> = [
module: require('./SnapshotExample'),
supportsTVOS: true,
},
{
key: 'StrictModeExample',
module: require('./StrictModeExample'),
},
{
key: 'TimerExample',
module: require('./TimerExample'),
Expand Down
47 changes: 47 additions & 0 deletions RNTester/js/StrictModeExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/

'use strict';

const React = require('react');
const {StrictMode} = React;
const ReactNative = require('react-native');
const {ScrollView, Text} = ReactNative;

type Props = $ReadOnly<{||}>;
type State = {|result: string|};

const componentsToTest = [ScrollView];

class StrictModeExample extends React.Component<Props, State> {
render() {
return (
<StrictMode>
{componentsToTest.map(Component => (
<Component key={Component.displayName}>
<Text>{Component.displayName}</Text>
</Component>
))}
</StrictMode>
);
}
}

exports.framework = 'React';
exports.title = 'StrictMode';
exports.description = 'See components in strict mode.';
exports.examples = [
{
title: 'Strict Mode',
render() {
return <StrictModeExample />;
},
},
];

0 comments on commit 2550ad8

Please sign in to comment.