forked from treehouse/mastodon
Fix unnecessary re-rendering of various components when typing in web UI (#15286)
parent
48bef17cc9
commit
9620ee90be
|
@ -97,7 +97,7 @@ class Status extends ImmutablePureComponent {
|
||||||
cachedMediaWidth: PropTypes.number,
|
cachedMediaWidth: PropTypes.number,
|
||||||
scrollKey: PropTypes.string,
|
scrollKey: PropTypes.string,
|
||||||
deployPictureInPicture: PropTypes.func,
|
deployPictureInPicture: PropTypes.func,
|
||||||
pictureInPicture: PropTypes.shape({
|
pictureInPicture: ImmutablePropTypes.contains({
|
||||||
inUse: PropTypes.bool,
|
inUse: PropTypes.bool,
|
||||||
available: PropTypes.bool,
|
available: PropTypes.bool,
|
||||||
}),
|
}),
|
||||||
|
@ -354,7 +354,7 @@ class Status extends ImmutablePureComponent {
|
||||||
status = status.get('reblog');
|
status = status.get('reblog');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pictureInPicture.inUse) {
|
if (pictureInPicture.get('inUse')) {
|
||||||
media = <PictureInPicturePlaceholder width={this.props.cachedMediaWidth} />;
|
media = <PictureInPicturePlaceholder width={this.props.cachedMediaWidth} />;
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
if (this.props.muted) {
|
if (this.props.muted) {
|
||||||
|
@ -381,7 +381,7 @@ class Status extends ImmutablePureComponent {
|
||||||
width={this.props.cachedMediaWidth}
|
width={this.props.cachedMediaWidth}
|
||||||
height={110}
|
height={110}
|
||||||
cacheWidth={this.props.cacheMediaWidth}
|
cacheWidth={this.props.cacheMediaWidth}
|
||||||
deployPictureInPicture={pictureInPicture.available ? this.handleDeployPictureInPicture : undefined}
|
deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Bundle>
|
</Bundle>
|
||||||
|
@ -404,7 +404,7 @@ class Status extends ImmutablePureComponent {
|
||||||
sensitive={status.get('sensitive')}
|
sensitive={status.get('sensitive')}
|
||||||
onOpenVideo={this.handleOpenVideo}
|
onOpenVideo={this.handleOpenVideo}
|
||||||
cacheWidth={this.props.cacheMediaWidth}
|
cacheWidth={this.props.cacheMediaWidth}
|
||||||
deployPictureInPicture={pictureInPicture.available ? this.handleDeployPictureInPicture : undefined}
|
deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
|
||||||
visible={this.state.showMedia}
|
visible={this.state.showMedia}
|
||||||
onToggleVisibility={this.handleToggleMediaVisibility}
|
onToggleVisibility={this.handleToggleMediaVisibility}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import Status from '../components/status';
|
import Status from '../components/status';
|
||||||
import { makeGetStatus } from '../selectors';
|
import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
|
||||||
import {
|
import {
|
||||||
replyCompose,
|
replyCompose,
|
||||||
mentionCompose,
|
mentionCompose,
|
||||||
|
@ -54,14 +54,11 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
|
const getPictureInPicture = makeGetPictureInPicture();
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
status: getStatus(state, props),
|
status: getStatus(state, props),
|
||||||
|
pictureInPicture: getPictureInPicture(state, props),
|
||||||
pictureInPicture: {
|
|
||||||
inUse: state.getIn(['meta', 'layout']) !== 'mobile' && state.get('picture_in_picture').statusId === props.id,
|
|
||||||
available: state.getIn(['meta', 'layout']) !== 'mobile',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return mapStateToProps;
|
return mapStateToProps;
|
||||||
|
|
|
@ -41,7 +41,10 @@ class DetailedStatus extends ImmutablePureComponent {
|
||||||
domain: PropTypes.string.isRequired,
|
domain: PropTypes.string.isRequired,
|
||||||
compact: PropTypes.bool,
|
compact: PropTypes.bool,
|
||||||
showMedia: PropTypes.bool,
|
showMedia: PropTypes.bool,
|
||||||
usingPiP: PropTypes.bool,
|
pictureInPicture: ImmutablePropTypes.contains({
|
||||||
|
inUse: PropTypes.bool,
|
||||||
|
available: PropTypes.bool,
|
||||||
|
}),
|
||||||
onToggleMediaVisibility: PropTypes.func,
|
onToggleMediaVisibility: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,7 +105,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
||||||
render () {
|
render () {
|
||||||
const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
|
const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
|
||||||
const outerStyle = { boxSizing: 'border-box' };
|
const outerStyle = { boxSizing: 'border-box' };
|
||||||
const { intl, compact, usingPiP } = this.props;
|
const { intl, compact, pictureInPicture } = this.props;
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -118,7 +121,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
||||||
outerStyle.height = `${this.state.height}px`;
|
outerStyle.height = `${this.state.height}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usingPiP) {
|
if (pictureInPicture.get('inUse')) {
|
||||||
media = <PictureInPicturePlaceholder />;
|
media = <PictureInPicturePlaceholder />;
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||||
|
|
|
@ -43,7 +43,7 @@ import {
|
||||||
import { initMuteModal } from '../../actions/mutes';
|
import { initMuteModal } from '../../actions/mutes';
|
||||||
import { initBlockModal } from '../../actions/blocks';
|
import { initBlockModal } from '../../actions/blocks';
|
||||||
import { initReport } from '../../actions/reports';
|
import { initReport } from '../../actions/reports';
|
||||||
import { makeGetStatus } from '../../selectors';
|
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
|
||||||
import { ScrollContainer } from 'react-router-scroll-4';
|
import { ScrollContainer } from 'react-router-scroll-4';
|
||||||
import ColumnBackButton from '../../components/column_back_button';
|
import ColumnBackButton from '../../components/column_back_button';
|
||||||
import ColumnHeader from '../../components/column_header';
|
import ColumnHeader from '../../components/column_header';
|
||||||
|
@ -72,6 +72,7 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
|
const getPictureInPicture = makeGetPictureInPicture();
|
||||||
|
|
||||||
const getAncestorsIds = createSelector([
|
const getAncestorsIds = createSelector([
|
||||||
(_, { id }) => id,
|
(_, { id }) => id,
|
||||||
|
@ -129,11 +130,12 @@ const makeMapStateToProps = () => {
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
const status = getStatus(state, { id: props.params.statusId });
|
const status = getStatus(state, { id: props.params.statusId });
|
||||||
let ancestorsIds = Immutable.List();
|
|
||||||
|
let ancestorsIds = Immutable.List();
|
||||||
let descendantsIds = Immutable.List();
|
let descendantsIds = Immutable.List();
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
ancestorsIds = getAncestorsIds(state, { id: status.get('in_reply_to_id') });
|
ancestorsIds = getAncestorsIds(state, { id: status.get('in_reply_to_id') });
|
||||||
descendantsIds = getDescendantsIds(state, { id: status.get('id') });
|
descendantsIds = getDescendantsIds(state, { id: status.get('id') });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +145,7 @@ const makeMapStateToProps = () => {
|
||||||
descendantsIds,
|
descendantsIds,
|
||||||
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
|
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
|
||||||
domain: state.getIn(['meta', 'domain']),
|
domain: state.getIn(['meta', 'domain']),
|
||||||
usingPiP: state.get('picture_in_picture').statusId === props.params.statusId,
|
pictureInPicture: getPictureInPicture(state, { id: props.params.statusId }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,7 +170,10 @@ class Status extends ImmutablePureComponent {
|
||||||
askReplyConfirmation: PropTypes.bool,
|
askReplyConfirmation: PropTypes.bool,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
domain: PropTypes.string.isRequired,
|
domain: PropTypes.string.isRequired,
|
||||||
usingPiP: PropTypes.bool,
|
pictureInPicture: ImmutablePropTypes.contains({
|
||||||
|
inUse: PropTypes.bool,
|
||||||
|
available: PropTypes.bool,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -492,7 +497,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let ancestors, descendants;
|
let ancestors, descendants;
|
||||||
const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl, domain, multiColumn, usingPiP } = this.props;
|
const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props;
|
||||||
const { fullscreen } = this.state;
|
const { fullscreen } = this.state;
|
||||||
|
|
||||||
if (status === null) {
|
if (status === null) {
|
||||||
|
@ -550,7 +555,7 @@ class Status extends ImmutablePureComponent {
|
||||||
domain={domain}
|
domain={domain}
|
||||||
showMedia={this.state.showMedia}
|
showMedia={this.state.showMedia}
|
||||||
onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
||||||
usingPiP={usingPiP}
|
pictureInPicture={pictureInPicture}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ActionBar
|
<ActionBar
|
||||||
|
|
|
@ -99,8 +99,13 @@ class ColumnsArea extends ImmutablePureComponent {
|
||||||
if (this.props.singleColumn !== prevProps.singleColumn && !this.props.singleColumn) {
|
if (this.props.singleColumn !== prevProps.singleColumn && !this.props.singleColumn) {
|
||||||
this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false);
|
this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false);
|
||||||
}
|
}
|
||||||
this.lastIndex = getIndex(this.context.router.history.location.pathname);
|
|
||||||
this.setState({ shouldAnimate: true });
|
const newIndex = getIndex(this.context.router.history.location.pathname);
|
||||||
|
|
||||||
|
if (this.lastIndex !== newIndex) {
|
||||||
|
this.lastIndex = newIndex;
|
||||||
|
this.setState({ shouldAnimate: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { List as ImmutableList, is } from 'immutable';
|
import { List as ImmutableList, Map as ImmutableMap, is } from 'immutable';
|
||||||
import { me } from '../initial_state';
|
import { me } from '../initial_state';
|
||||||
|
|
||||||
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
|
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
|
||||||
|
@ -121,6 +121,16 @@ export const makeGetStatus = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const makeGetPictureInPicture = () => {
|
||||||
|
return createSelector([
|
||||||
|
(state, { id }) => state.get('picture_in_picture').statusId === id,
|
||||||
|
(state) => state.getIn(['meta', 'layout']) !== 'mobile',
|
||||||
|
], (inUse, available) => ImmutableMap({
|
||||||
|
inUse: inUse && available,
|
||||||
|
available,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const getAlertsBase = state => state.get('alerts');
|
const getAlertsBase = state => state.get('alerts');
|
||||||
|
|
||||||
export const getAlerts = createSelector([getAlertsBase], (base) => {
|
export const getAlerts = createSelector([getAlertsBase], (base) => {
|
||||||
|
|
Loading…
Reference in New Issue