Reduce updates caused by typing (#604)

* prevent index page from updating

* implement shouldComponentUpdate for ExportMenu

* replace componentDidUpdate with updateState in Editor

* replace shallowCompare with React.memo

* add flex-basis to prevent jank
main
Sean 6 years ago committed by Michael Fix
parent 0aa1d7404f
commit 5206dc4ef1

@ -6,7 +6,6 @@ import { DragDropContext } from 'react-dnd'
import domtoimage from 'dom-to-image'
import ReadFileDropContainer, { DATA_URL, TEXT } from 'dropperx'
import Spinner from 'react-spinner'
import shallowCompare from 'react-addons-shallow-compare'
// Ours
import Button from './Button'
@ -102,7 +101,7 @@ class Editor extends React.Component {
newState.language = unescapeHtml(newState.language)
}
this.setState(newState)
this.updateState(newState)
window.addEventListener('offline', this.setOffline)
window.addEventListener('online', this.setOnline)
@ -113,18 +112,13 @@ class Editor extends React.Component {
window.removeEventListener('online', this.setOnline)
}
componentDidUpdate(prevProps, prevState) {
// this.props ensures props are not compared, only state
if (shallowCompare(this, this.props, prevState)) {
this.props.onUpdate(this.state)
}
}
updateState = updates => this.setState(updates, () => this.props.onUpdate(this.state))
updateCode = code => this.setState({ code })
updateAspectRatio = aspectRatio => this.setState({ aspectRatio })
updateTitleBar = titleBar => this.setState({ titleBar })
setOffline = () => this.setState({ online: false })
setOnline = () => this.setState({ online: true })
updateCode = code => this.updateState({ code })
updateAspectRatio = aspectRatio => this.updateState({ aspectRatio })
updateTitleBar = titleBar => this.updateState({ titleBar })
setOffline = () => this.updateState({ online: false })
setOnline = () => this.updateState({ online: true })
async getCarbonImage(
{
@ -208,9 +202,9 @@ class Editor extends React.Component {
}
updateSetting(key, value) {
this.setState({ [key]: value })
this.updateState({ [key]: value })
if (Object.prototype.hasOwnProperty.call(DEFAULT_SETTINGS, key)) {
this.setState({ preset: null })
this.updateState({ preset: null })
}
}
@ -231,29 +225,29 @@ class Editor extends React.Component {
}
resetDefaultSettings() {
this.setState({ ...DEFAULT_SETTINGS, preset: DEFAULT_PRESET_ID })
this.updateState({ ...DEFAULT_SETTINGS, preset: DEFAULT_PRESET_ID })
this.props.onReset()
}
upload() {
this.setState({ uploading: true })
this.updateState({ uploading: true })
this.getCarbonImage({ format: 'png' })
.then(this.props.api.tweet.bind(null, this.state.code || DEFAULT_CODE))
// eslint-disable-next-line
.catch(console.error)
.then(() => this.setState({ uploading: false }))
.then(() => this.updateState({ uploading: false }))
}
onDrop([file]) {
if (isImage(file)) {
this.setState({
this.updateState({
backgroundImage: file.content,
backgroundImageSelection: null,
backgroundMode: 'image',
preset: null
})
} else {
this.setState({ code: file.content, language: 'auto' })
this.updateState({ code: file.content, language: 'auto' })
}
}
@ -267,13 +261,13 @@ class Editor extends React.Component {
updateBackground({ photographer, ...changes } = {}) {
if (photographer) {
this.setState(({ code = DEFAULT_CODE }) => ({
this.updateState(({ code = DEFAULT_CODE }) => ({
...changes,
code: code + `\n\n// Photo by ${photographer.name} on Unsplash`,
preset: null
}))
} else {
this.setState({ ...changes, preset: null })
this.updateState({ ...changes, preset: null })
}
}
@ -284,7 +278,7 @@ class Editor extends React.Component {
// create toast here in the future
})
applyPreset = ({ id: preset, ...settings }) => this.setState({ preset, ...settings })
applyPreset = ({ id: preset, ...settings }) => this.updateState({ preset, ...settings })
render() {
const {

@ -17,6 +17,46 @@ const toIFrame = url =>
</iframe>
`
const CopyEmbed = withRouter(
React.memo(
({ router: { asPath } }) => (
<React.Fragment>
<CopyButton text={toIFrame(asPath)}>
{({ copied }) => (
<button className="copy-button">{copied ? 'Copied!' : 'Copy Embed'}</button>
)}
</CopyButton>
<style jsx>
{`
.copy-button {
display: flex;
flex: 1;
flex-basis: 68px;
justify-content: center;
align-items: center;
padding: 12px 16px;
font-size: 12px;
white-space: nowrap;
user-select: none;
cursor: pointer;
outline: none;
border: none;
background: inherit;
color: ${COLORS.PURPLE};
border-right: 1px solid ${COLORS.PURPLE};
}
.copy-button:hover {
opacity: 1;
}
`}
</style>
</React.Fragment>
),
(prevProps, nextProps) => prevProps.router.asPath === nextProps.router.asPath
)
)
class ExportMenu extends React.PureComponent {
state = {
isVisible: false
@ -33,7 +73,7 @@ class ExportMenu extends React.PureComponent {
handleExport = format => () => this.props.export(format)
render() {
const { exportSize, filename, router } = this.props
const { exportSize, filename } = this.props
const { isVisible } = this.state
return (
@ -77,11 +117,7 @@ class ExportMenu extends React.PureComponent {
<button className="open-button" onClick={this.handleExport('open')}>
Open
</button>
<CopyButton text={toIFrame(router.asPath)}>
{({ copied }) => (
<button className="copy-button">{copied ? 'Copied!' : 'Copy Embed'}</button>
)}
</CopyButton>
<CopyEmbed />
<div className="save-container">
<span>Save as</span>
<div>
@ -187,7 +223,6 @@ class ExportMenu extends React.PureComponent {
opacity: 1;
}
.copy-button,
.open-button,
.save-container {
display: flex;
@ -197,11 +232,6 @@ class ExportMenu extends React.PureComponent {
padding: 12px 16px;
}
.copy-button {
white-space: nowrap;
}
.copy-button,
.open-button {
border-right: 1px solid ${COLORS.PURPLE};
}
@ -229,4 +259,4 @@ class ExportMenu extends React.PureComponent {
}
}
export default withRouter(enhanceWithClickOutside(ExportMenu))
export default enhanceWithClickOutside(ExportMenu)

@ -10,6 +10,8 @@ import { updateQueryString } from '../lib/routing'
import { saveSettings, clearSettings, omit } from '../lib/util'
class Index extends React.Component {
shouldComponentUpdate = () => false
onEditorUpdate = state => {
updateQueryString(this.props.router, state)
saveSettings(

Loading…
Cancel
Save