Skip to content

Commit

Permalink
Upgrade React Redux and Redux Form (#37438)
Browse files Browse the repository at this point in the history
* fix(deps): update dependency redux-form to v8

* fix(deps): update dependency react-redux to v7

* ImageEditorCanvas: change react-redux withRef to forwardRef, modernize the component

React Redux ref API has changed in 7.0.0.

Modernization includes:
- use modern refs
- use arrow functions for bound methods
- every variable has its own `const` decl

* Zoninator Search Autocomplete: change react-redux withRef to forwardRef

* Notifications: use react-redux forwardRef to get list element

* Get Redux store from new React context in TinyMCE wrappers

* WebPaymentBox unit test: pass mock Redux store by wrappingComponent enzyme option

Instead of using the legacy React context, which is an implementation detail of particular
React Redux version, use the Enzyme's `wrappingComponent` option to render a mock Redux
provider above the tested component.

* WithContactDetailsValidation Unit Test: pass Redux store as wrappingComponent, use full mount

React Redux 7.x no longer supports `store` prop for `Provider`, and uses the new `React.createContext()`
instead of the legacy context. That requires an update of the unit tests.

- use `wrappingComponent` option to activate a mock Redux provider
- switch to full mount, as `wrappingComponent` doesn't work with `useContext` in Enzyme (enzymejs/enzyme#2176)

* Jetpack Connect Help Button: convert to hooked functional component with useDispatch

* PluginsList: rewrite tests to use Enzyme

* DomainManagement.List: rewrite tests to use Enzyme
  • Loading branch information
jsnajdr authored Nov 12, 2019
1 parent 173ada7 commit ba82ba2
Show file tree
Hide file tree
Showing 20 changed files with 363 additions and 364 deletions.
20 changes: 11 additions & 9 deletions apps/notifications/src/panel/templates/index.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
/**
* @module templates/index
* External dependencies
*/

import React from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import { find, findIndex, matchesProperty } from 'lodash';

/**
* Internal dependencies
*/
import BackButton from './button-back';
import NavButton from './nav-button';
import NoteList from './note-list';
Expand Down Expand Up @@ -81,7 +83,7 @@ class Layout extends React.Component {
this.props.global.client = this.props.client;
this.props.global.toggleNavigation = this.toggleNavigation;

if ( 'undefined' == typeof this.props.global.navigation ) {
if ( 'undefined' === typeof this.props.global.navigation ) {
this.props.global.navigation = {};

/* Keyboard shortcutes */
Expand Down Expand Up @@ -434,14 +436,14 @@ class Layout extends React.Component {
this.noteList = ref;
};

storeNoteListVisibilityUpdater = updater => {
this.noteListVisibilityUpdater = updater;
};

storeDetailViewRef = ref => {
this.detailView = ref;
};

storeNoteListVisibilityUpdater = updater => {
this.noteListVisibilityUpdater = updater;
};

render() {
const currentNote = find(
this.props.notes,
Expand Down Expand Up @@ -482,7 +484,7 @@ class Layout extends React.Component {
className="wpnc__prev"
isEnabled={
( filteredNotes[ 0 ] &&
filteredNotes[ 0 ].id != this.props.selectedNoteId ) ||
filteredNotes[ 0 ].id !== this.props.selectedNoteId ) ||
false
}
navigate={ this.navigateToPrevNote }
Expand All @@ -492,7 +494,7 @@ class Layout extends React.Component {
className="wpnc__next"
isEnabled={
( filteredNotes[ 0 ] &&
filteredNotes[ filteredNotes.length - 1 ].id !=
filteredNotes[ filteredNotes.length - 1 ].id !==
this.props.selectedNoteId ) ||
false
}
Expand Down
52 changes: 24 additions & 28 deletions apps/notifications/src/panel/templates/note-list.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
/**
* External dependencies
*/
import ReactDOM from 'react-dom';
import React from 'react';
import { connect } from 'react-redux';
import { localize } from 'i18n-calypso';
import classNames from 'classnames';
import { findIndex, groupBy, reduce, zip } from 'lodash';

/**
* Internal dependencies
*/
import actions from '../state/actions';
import getFilterName from '../state/selectors/get-filter-name';
import getIsLoading from '../state/selectors/get-is-loading';
Expand All @@ -21,18 +27,10 @@ import Spinner from './spinner';
import StatusBar from './status-bar';
import UndoListItem from './undo-list-item';

var DAY_MILLISECONDS = 24 * 60 * 60 * 1000;
const DAY_MILLISECONDS = 24 * 60 * 60 * 1000;

// from $wpnc__title-bar-height in boot/sizes.scss
var TITLE_OFFSET = 38;

const getDOMNodeOrElse = ref => {
try {
return ReactDOM.findDOMNode( ref );
} catch ( e ) {
return undefined;
}
};
const TITLE_OFFSET = 38;

export class NoteList extends React.Component {
static defaultProps = {
Expand All @@ -47,6 +45,8 @@ export class NoteList extends React.Component {
statusMessage: '',
};

noteElements = {};

UNSAFE_componentWillMount() {
this.props.global.updateStatusBar = this.updateStatusBar;
this.props.global.resetStatusBar = this.resetStatusBar;
Expand Down Expand Up @@ -153,11 +153,11 @@ export class NoteList extends React.Component {
};

ensureSelectedNoteVisibility = () => {
var scrollTarget = null,
selectedNote = this.props.selectedNote,
noteElement = getDOMNodeOrElse( ( this.notes || {} )[ selectedNote ] ),
listElement = null,
topPadding;
let scrollTarget = null;
const selectedNote = this.props.selectedNote;
const noteElement = this.noteElements[ selectedNote ];
let listElement = null;
let topPadding;

if ( null === selectedNote || ! noteElement ) {
scrollTarget = this.state.scrollY + 1;
Expand All @@ -166,7 +166,7 @@ export class NoteList extends React.Component {
listElement = this.noteList;
topPadding = listElement.offsetTop + TITLE_OFFSET;

var yOffset = listElement.parentNode.scrollTop;
const yOffset = listElement.parentNode.scrollTop;

if ( noteElement.offsetTop - yOffset <= topPadding ) {
/* Scroll up if note is above viewport */
Expand All @@ -182,15 +182,12 @@ export class NoteList extends React.Component {
}
};

storeNote = ref => {
if ( ! ref ) {
return;
storeNote = noteId => ref => {
if ( ref ) {
this.noteElements[ noteId ] = ref;
} else {
delete this.noteElements[ noteId ];
}

this.notes = {
...this.notes,
[ ref.props[ 'data-note-id' ] ]: ref,
};
};

storeNoteList = ref => {
Expand Down Expand Up @@ -245,7 +242,7 @@ export class NoteList extends React.Component {
const timeGroups = zip( timeBoundaries.slice( 0, -1 ), timeBoundaries.slice( 1 ) );

const createNoteComponent = note => {
if ( this.state.undoNote && note.id == this.state.undoNote.id ) {
if ( this.state.undoNote && note.id === this.state.undoNote.id ) {
return (
<UndoListItem
ref={ this.storeUndoBar }
Expand All @@ -264,9 +261,8 @@ export class NoteList extends React.Component {
return (
<Note
note={ note }
ref={ this.storeNote }
ref={ this.storeNote( note.id ) }
key={ 'note-' + note.id }
data-note-id={ note.id }
detailView={ false }
client={ this.props.client }
global={ this.props.global }
Expand Down Expand Up @@ -380,5 +376,5 @@ export default connect(
mapStateToProps,
mapDispatchToProps,
null,
{ pure: false }
{ forwardRef: true }
)( localize( NoteList ) );
19 changes: 15 additions & 4 deletions apps/notifications/src/panel/templates/note.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/**
* External dependencies
*/
import React from 'react';
import { connect } from 'react-redux';
import classNames from 'classnames';

/**
* Internal dependencies
*/
import getIsNoteApproved from '../state/selectors/get-is-note-approved';
import getIsNoteRead from '../state/selectors/get-is-note-read';

Expand All @@ -14,7 +20,7 @@ import { getActions } from '../helpers/notes';
const hasBadge = body =>
body.some( ( { media } ) => media && media.some( ( { type } ) => 'badge' === type ) );

export const Note = props => {
export const Note = React.forwardRef( ( props, ref ) => {
const { currentNote, detailView, global, isApproved, isRead, note, selectedNote } = props;

let hasCommentReply = false;
Expand Down Expand Up @@ -47,7 +53,7 @@ export const Note = props => {
} );

return (
<li id={ 'note-' + note.id } className={ classes }>
<li id={ 'note-' + note.id } className={ classes } ref={ ref }>
{ detailView && note.header && note.header.length > 0 && (
<SummaryInSingle key={ 'note-summary-single-' + note.id } note={ note } />
) }
Expand All @@ -62,11 +68,16 @@ export const Note = props => {
{ detailView && <NoteBody key={ 'note-body-' + note.id } note={ note } global={ global } /> }
</li>
);
};
} );

const mapStateToProps = ( state, { note } ) => ( {
isApproved: getIsNoteApproved( state, note ),
isRead: getIsNoteRead( state, note ),
} );

export default connect( mapStateToProps )( Note );
export default connect(
mapStateToProps,
null,
null,
{ forwardRef: true }
)( Note );
Loading

0 comments on commit ba82ba2

Please sign in to comment.