Merge pull request #125 from Gargron/fix-useless-rerenders

Remove function binds in render wherever possible, use PureComponent
nolan/hinaloe-test
Etienne Lemay 2017-09-30 11:42:03 -04:00 committed by GitHub
commit bbd4fbe764
6 changed files with 76 additions and 46 deletions

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import SVGs from '../svgs' import SVGs from '../svgs'
export default class Anchors extends React.Component { export default class Anchors extends React.PureComponent {
constructor(props) { constructor(props) {
super(props) super(props)
@ -14,6 +14,15 @@ export default class Anchors extends React.Component {
this.state = { this.state = {
selected: defaultCategory.name selected: defaultCategory.name
} }
this.handleClick = this.handleClick.bind(this)
}
handleClick (e) {
var index = e.currentTarget.getAttribute('data-index')
var { categories, onAnchorClick } = this.props
onAnchorClick(categories[index], index)
} }
render() { render() {
@ -33,7 +42,8 @@ export default class Anchors extends React.Component {
<span <span
key={name} key={name}
title={i18n.categories[name.toLowerCase()]} title={i18n.categories[name.toLowerCase()]}
onClick={() => onAnchorClick(category, i)} data-index={i}
onClick={this.handleClick}
className={`emoji-mart-anchor ${isSelected ? 'emoji-mart-anchor-selected' : ''}`} className={`emoji-mart-anchor ${isSelected ? 'emoji-mart-anchor-selected' : ''}`}
style={{ color: isSelected ? color : null }} style={{ color: isSelected ? color : null }}
> >

View File

@ -5,6 +5,13 @@ import frequently from '../utils/frequently'
import { Emoji } from '.' import { Emoji } from '.'
export default class Category extends React.Component { export default class Category extends React.Component {
constructor(props) {
super(props)
this.setContainerRef = this.setContainerRef.bind(this)
this.setLabelRef = this.setLabelRef.bind(this)
}
componentDidMount() { componentDidMount() {
this.parent = this.container.parentNode this.parent = this.container.parentNode
@ -133,29 +140,26 @@ export default class Category extends React.Component {
} }
} }
return <div ref={this.setContainerRef.bind(this)} className={`emoji-mart-category ${emojis && !emojis.length ? 'emoji-mart-no-results' : ''}`} style={containerStyles}> return <div ref={this.setContainerRef} className={`emoji-mart-category ${emojis && !emojis.length ? 'emoji-mart-no-results' : ''}`} style={containerStyles}>
<div style={labelStyles} data-name={name} className='emoji-mart-category-label'> <div style={labelStyles} data-name={name} className='emoji-mart-category-label'>
<span style={labelSpanStyles} ref={this.setLabelRef.bind(this)}>{i18n.categories[name.toLowerCase()]}</span> <span style={labelSpanStyles} ref={this.setLabelRef}>{i18n.categories[name.toLowerCase()]}</span>
</div> </div>
{emojis && emojis.map((emoji) => {emojis && emojis.map((emoji) =>
Emoji({ Emoji({ emoji: emoji, ...emojiProps })
emoji: emoji,
...emojiProps
})
)} )}
{emojis && !emojis.length && {emojis && !emojis.length &&
<div> <div>
<div> <div>
{Emoji({ {Emoji({
...emojiProps, ...emojiProps,
size: 38, size: 38,
emoji: 'sleuth_or_spy', emoji: 'sleuth_or_spy',
onOver: null, onOver: null,
onLeave: null, onLeave: null,
onClick: null, onClick: null,
})} })}
</div> </div>
<div className='emoji-mart-no-results-label'> <div className='emoji-mart-no-results-label'>

View File

@ -32,7 +32,7 @@ const I18N = {
}, },
} }
export default class Picker extends React.Component { export default class Picker extends React.PureComponent {
constructor(props) { constructor(props) {
super(props) super(props)
@ -115,6 +115,19 @@ export default class Picker extends React.Component {
} }
this.categories.unshift(SEARCH_CATEGORY) this.categories.unshift(SEARCH_CATEGORY)
this.setAnchorsRef = this.setAnchorsRef.bind(this)
this.handleAnchorClick = this.handleAnchorClick.bind(this)
this.setSearchRef = this.setSearchRef.bind(this)
this.handleSearch = this.handleSearch.bind(this)
this.setScrollRef = this.setScrollRef.bind(this)
this.handleScroll = this.handleScroll.bind(this)
this.handleScrollPaint = this.handleScrollPaint.bind(this)
this.handleEmojiOver = this.handleEmojiOver.bind(this)
this.handleEmojiLeave = this.handleEmojiLeave.bind(this)
this.handleEmojiClick = this.handleEmojiClick.bind(this)
this.setPreviewRef = this.setPreviewRef.bind(this)
this.handleSkinChange = this.handleSkinChange.bind(this)
} }
componentWillReceiveProps(props) { componentWillReceiveProps(props) {
@ -206,7 +219,7 @@ export default class Picker extends React.Component {
handleScroll() { handleScroll() {
if (!this.waitingForPaint) { if (!this.waitingForPaint) {
this.waitingForPaint = true this.waitingForPaint = true
window.requestAnimationFrame(this.handleScrollPaint.bind(this)) window.requestAnimationFrame(this.handleScrollPaint)
} }
} }
@ -368,17 +381,17 @@ export default class Picker extends React.Component {
return <div style={{width: width, ...style}} className='emoji-mart'> return <div style={{width: width, ...style}} className='emoji-mart'>
<div className='emoji-mart-bar'> <div className='emoji-mart-bar'>
<Anchors <Anchors
ref={this.setAnchorsRef.bind(this)} ref={this.setAnchorsRef}
i18n={this.i18n} i18n={this.i18n}
color={color} color={color}
categories={this.categories} categories={this.categories}
onAnchorClick={this.handleAnchorClick.bind(this)} onAnchorClick={this.handleAnchorClick}
/> />
</div> </div>
<Search <Search
ref={this.setSearchRef.bind(this)} ref={this.setSearchRef}
onSearch={this.handleSearch.bind(this)} onSearch={this.handleSearch}
i18n={this.i18n} i18n={this.i18n}
emojisToShowFilter={emojisToShowFilter} emojisToShowFilter={emojisToShowFilter}
include={include} include={include}
@ -387,7 +400,7 @@ export default class Picker extends React.Component {
autoFocus={autoFocus} autoFocus={autoFocus}
/> />
<div ref={this.setScrollRef.bind(this)} className='emoji-mart-scroll' onScroll={this.handleScroll.bind(this)}> <div ref={this.setScrollRef} className='emoji-mart-scroll' onScroll={this.handleScroll}>
{this.getCategories().map((category, i) => { {this.getCategories().map((category, i) => {
return <Category return <Category
ref={this.setCategoryRef.bind(this, `category-${i}`)} ref={this.setCategoryRef.bind(this, `category-${i}`)}
@ -407,9 +420,9 @@ export default class Picker extends React.Component {
sheetSize: sheetSize, sheetSize: sheetSize,
forceSize: native, forceSize: native,
backgroundImageFn: backgroundImageFn, backgroundImageFn: backgroundImageFn,
onOver: this.handleEmojiOver.bind(this), onOver: this.handleEmojiOver,
onLeave: this.handleEmojiLeave.bind(this), onLeave: this.handleEmojiLeave,
onClick: this.handleEmojiClick.bind(this), onClick: this.handleEmojiClick,
}} }}
/> />
})} })}
@ -417,7 +430,7 @@ export default class Picker extends React.Component {
{showPreview && <div className='emoji-mart-bar'> {showPreview && <div className='emoji-mart-bar'>
<Preview <Preview
ref={this.setPreviewRef.bind(this)} ref={this.setPreviewRef}
title={title} title={title}
emoji={emoji} emoji={emoji}
emojiProps={{ emojiProps={{
@ -430,7 +443,7 @@ export default class Picker extends React.Component {
}} }}
skinsProps={{ skinsProps={{
skin: skin, skin: skin,
onChange: this.handleSkinChange.bind(this) onChange: this.handleSkinChange
}} }}
/> />
</div>} </div>}

View File

@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import { Emoji, Skins } from '.' import { Emoji, Skins } from '.'
import { getData } from '../utils' import { getData } from '../utils'
export default class Preview extends React.Component { export default class Preview extends React.PureComponent {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { emoji: null } this.state = { emoji: null }
@ -31,11 +31,7 @@ export default class Preview extends React.Component {
return <div className='emoji-mart-preview'> return <div className='emoji-mart-preview'>
<div className='emoji-mart-preview-emoji'> <div className='emoji-mart-preview-emoji'>
{Emoji({ {Emoji({ key: emoji.id, emoji: emoji, ...emojiProps })}
key: emoji.id,
emoji: emoji,
...emojiProps,
})}
</div> </div>
<div className='emoji-mart-preview-data'> <div className='emoji-mart-preview-data'>
@ -55,10 +51,7 @@ export default class Preview extends React.Component {
} else { } else {
return <div className='emoji-mart-preview'> return <div className='emoji-mart-preview'>
<div className='emoji-mart-preview-emoji'> <div className='emoji-mart-preview-emoji'>
{idleEmoji && idleEmoji.length && Emoji({ {idleEmoji && idleEmoji.length && Emoji({ emoji: idleEmoji, ...emojiProps })}
emoji: idleEmoji,
...emojiProps,
})}
</div> </div>
<div className='emoji-mart-preview-data'> <div className='emoji-mart-preview-data'>

View File

@ -2,7 +2,14 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import emojiIndex from '../utils/emoji-index' import emojiIndex from '../utils/emoji-index'
export default class Search extends React.Component { export default class Search extends React.PureComponent {
constructor (props) {
super(props)
this.setRef = this.setRef.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange() { handleChange() {
var value = this.input.value var value = this.input.value
@ -28,9 +35,9 @@ export default class Search extends React.Component {
return <div className='emoji-mart-search'> return <div className='emoji-mart-search'>
<input <input
ref={this.setRef.bind(this)} ref={this.setRef}
type='text' type='text'
onChange={this.handleChange.bind(this)} onChange={this.handleChange}
placeholder={i18n.search} placeholder={i18n.search}
autoFocus={autoFocus} autoFocus={autoFocus}
/> />

View File

@ -1,16 +1,19 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
export default class Skins extends React.Component { export default class Skins extends React.PureComponent {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
opened: false, opened: false,
} }
this.handleClick = this.handleClick.bind(this)
} }
handleClick(skin) { handleClick(e) {
var skin = e.currentTarget.getAttribute('data-skin')
var { onChange } = this.props var { onChange } = this.props
if (!this.state.opened) { if (!this.state.opened) {
@ -39,9 +42,9 @@ export default class Skins extends React.Component {
className={`emoji-mart-skin-swatch ${selected ? 'emoji-mart-skin-swatch-selected' : ''}`} className={`emoji-mart-skin-swatch ${selected ? 'emoji-mart-skin-swatch-selected' : ''}`}
> >
<span <span
onClick={() => this.handleClick(skinTone)} onClick={this.handleClick}
className={`emoji-mart-skin emoji-mart-skin-tone-${skinTone}`}> data-skin={skinTone}
</span> className={`emoji-mart-skin emoji-mart-skin-tone-${skinTone}`} />
</span> </span>
) )
} }