[FIX] Messagebox onChangeText issues (#1252)

* Stop ongoing debounces on messagebox unmount

* Immediately change send icon, but keep debouncing others

* Make CustomEmoji stateless function

* Fix mentions keyExtractor
This commit is contained in:
Diego Mello 2019-09-27 16:17:29 -03:00 committed by GitHub
parent d9f7ff836d
commit 3ee97881f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 42 deletions

View File

@ -2,28 +2,25 @@ import React from 'react';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
export default class CustomEmoji extends React.Component { const CustomEmoji = React.memo(({ baseUrl, emoji, style }) => (
static propTypes = { <FastImage
baseUrl: PropTypes.string.isRequired, style={style}
emoji: PropTypes.object.isRequired, source={{
style: PropTypes.any uri: `${ baseUrl }/emoji-custom/${ encodeURIComponent(emoji.content || emoji.name) }.${ emoji.extension }`,
} priority: FastImage.priority.high
}}
resizeMode={FastImage.resizeMode.contain}
/>
), (prevProps, nextProps) => {
const prevEmoji = prevProps.emoji.content || prevProps.emoji.name;
const nextEmoji = nextProps.emoji.content || nextProps.emoji.name;
return prevEmoji === nextEmoji;
});
shouldComponentUpdate() { CustomEmoji.propTypes = {
return false; baseUrl: PropTypes.string.isRequired,
} emoji: PropTypes.object.isRequired,
style: PropTypes.any
};
render() { export default CustomEmoji;
const { baseUrl, emoji, style } = this.props;
return (
<FastImage
style={style}
source={{
uri: `${ baseUrl }/emoji-custom/${ encodeURIComponent(emoji.content || emoji.name) }.${ emoji.extension }`,
priority: FastImage.priority.high
}}
resizeMode={FastImage.resizeMode.contain}
/>
);
}
}

View File

@ -224,12 +224,34 @@ class MessageBox extends Component {
componentWillUnmount() { componentWillUnmount() {
console.countReset(`${ this.constructor.name }.render calls`); console.countReset(`${ this.constructor.name }.render calls`);
if (this.onChangeText && this.onChangeText.stop) {
this.onChangeText.stop();
}
if (this.getUsers && this.getUsers.stop) {
this.getUsers.stop();
}
if (this.getRooms && this.getRooms.stop) {
this.getRooms.stop();
}
if (this.getEmojis && this.getEmojis.stop) {
this.getEmojis.stop();
}
if (this.getSlashCommands && this.getSlashCommands.stop) {
this.getSlashCommands.stop();
}
} }
onChangeText = debounce(async(text) => { onChangeText = (text) => {
const db = database.active;
const isTextEmpty = text.length === 0; const isTextEmpty = text.length === 0;
this.setShowSend(!isTextEmpty); this.setShowSend(!isTextEmpty);
this.debouncedOnChangeText(text);
}
// eslint-disable-next-line react/sort-comp
debouncedOnChangeText = debounce(async(text) => {
const db = database.active;
const isTextEmpty = text.length === 0;
// this.setShowSend(!isTextEmpty);
this.handleTyping(!isTextEmpty); this.handleTyping(!isTextEmpty);
this.setInput(text); this.setInput(text);
// matches if their is text that stats with '/' and group the command and params so we can use it "/command params" // matches if their is text that stats with '/' and group the command and params so we can use it "/command params"
@ -248,25 +270,29 @@ class MessageBox extends Component {
} }
if (!isTextEmpty) { if (!isTextEmpty) {
const { start, end } = this.component._lastNativeSelection; try {
const cursor = Math.max(start, end); const { start, end } = this.component._lastNativeSelection;
const lastNativeText = this.component._lastNativeText; const cursor = Math.max(start, end);
// matches if text either starts with '/' or have (@,#,:) then it groups whatever comes next of mention type const lastNativeText = this.component._lastNativeText || '';
const regexp = /(#|@|:|^\/)([a-z0-9._-]+)$/im; // matches if text either starts with '/' or have (@,#,:) then it groups whatever comes next of mention type
const result = lastNativeText.substr(0, cursor).match(regexp); const regexp = /(#|@|:|^\/)([a-z0-9._-]+)$/im;
if (!result) { const result = lastNativeText.substr(0, cursor).match(regexp);
const slash = lastNativeText.match(/^\/$/); // matches only '/' in input if (!result) {
if (slash) { const slash = lastNativeText.match(/^\/$/); // matches only '/' in input
return this.identifyMentionKeyword('', MENTIONS_TRACKING_TYPE_COMMANDS); if (slash) {
return this.identifyMentionKeyword('', MENTIONS_TRACKING_TYPE_COMMANDS);
}
return this.stopTrackingMention();
} }
return this.stopTrackingMention(); const [, lastChar, name] = result;
this.identifyMentionKeyword(name, lastChar);
} catch (e) {
log(e);
} }
const [, lastChar, name] = result;
this.identifyMentionKeyword(name, lastChar);
} else { } else {
this.stopTrackingMention(); this.stopTrackingMention();
} }
}, 100, true) }, 100)
onKeyboardResigned = () => { onKeyboardResigned = () => {
this.closeEmoji(); this.closeEmoji();
@ -339,10 +365,10 @@ class MessageBox extends Component {
getFixedMentions = (keyword) => { getFixedMentions = (keyword) => {
let result = []; let result = [];
if ('all'.indexOf(keyword) !== -1) { if ('all'.indexOf(keyword) !== -1) {
result = [{ _id: -1, username: 'all' }]; result = [{ id: -1, username: 'all' }];
} }
if ('here'.indexOf(keyword) !== -1) { if ('here'.indexOf(keyword) !== -1) {
result = [{ _id: -2, username: 'here' }, ...result]; result = [{ id: -2, username: 'here' }, ...result];
} }
return result; return result;
} }
@ -813,8 +839,9 @@ class MessageBox extends Component {
<FlatList <FlatList
style={styles.mentionList} style={styles.mentionList}
data={mentions} data={mentions}
extraData={mentions}
renderItem={this.renderMentionItem} renderItem={this.renderMentionItem}
keyExtractor={item => item._id || item.username || item.command || item} keyExtractor={item => item.id || item.username || item.command || item}
keyboardShouldPersistTaps='always' keyboardShouldPersistTaps='always'
/> />
</ScrollView> </ScrollView>