zl-react-native-gifted-chat
Version:
The most complete chat UI for React Native, based on 'react-native-gifted-chat'
179 lines (157 loc) • 4.67 kB
JavaScript
import React from 'react';
import {
ListView,
View,
} from 'react-native';
import shallowequal from 'shallowequal';
import InvertibleScrollView from 'react-native-invertible-scroll-view';
import md5 from 'md5';
import LoadEarlier from './LoadEarlier';
import Message from './Message';
export default class MessageContainer extends React.Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
this.renderFooter = this.renderFooter.bind(this);
this.renderLoadEarlier = this.renderLoadEarlier.bind(this);
this.renderScrollComponent = this.renderScrollComponent.bind(this);
const dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => {
return r1.hash !== r2.hash;
}
});
const messagesData = this.prepareMessages(props.messages);
this.state = {
dataSource: dataSource.cloneWithRows(messagesData.blob, messagesData.keys)
};
}
prepareMessages(messages) {
return {
keys: messages.map(m => m._id),
blob: messages.reduce((o, m, i) => {
const previousMessage = messages[i + 1] || {};
const nextMessage = messages[i - 1] || {};
// add next and previous messages to hash to ensure updates
const toHash = JSON.stringify(m) + previousMessage._id + nextMessage._id;
o[m._id] = {
...m,
previousMessage,
nextMessage,
hash: md5(toHash)
};
return o;
}, {})
};
}
shouldComponentUpdate(nextProps, nextState) {
if (!shallowequal(this.props, nextProps)) {
return true;
}
if (!shallowequal(this.state, nextState)) {
return true;
}
return false;
}
componentWillReceiveProps(nextProps) {
if (this.props.messages === nextProps.messages) {
return;
}
const messagesData = this.prepareMessages(nextProps.messages);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(messagesData.blob, messagesData.keys)
});
}
renderFooter() {
if (this.props.renderFooter) {
const footerProps = {
...this.props,
};
return this.props.renderFooter(footerProps);
}
return null;
}
renderLoadEarlier() {
if (this.props.loadEarlier === true) {
const loadEarlierProps = {
...this.props,
};
if (this.props.renderLoadEarlier) {
return this.props.renderLoadEarlier(loadEarlierProps);
}
return (
<LoadEarlier {...loadEarlierProps}/>
);
}
return null;
}
scrollTo(options) {
this._invertibleScrollViewRef.scrollTo(options);
}
renderRow(message, sectionId, rowId) {
if (!message._id) {
console.warn('GiftedChat: `_id` is missing for message', JSON.stringify(message));
}
if (!message.user) {
console.warn('GiftedChat: `user` is missing for message', JSON.stringify(message));
message.user = {};
}
const messageProps = {
...this.props,
key: message._id,
currentMessage: message,
previousMessage: message.previousMessage,
nextMessage: message.nextMessage,
position: message.user._id === this.props.user._id ? 'right' : 'left',
};
if (this.props.renderMessage) {
return this.props.renderMessage(messageProps);
}
return <Message {...messageProps}/>;
}
renderScrollComponent(props) {
const invertibleScrollViewProps = this.props.invertibleScrollViewProps;
console.log('invert')
return (
<InvertibleScrollView
{...props}
{...invertibleScrollViewProps}
keyboardShouldPersistTaps={false}
keyboardDismissMode={'on-drag'}
ref={component => this._invertibleScrollViewRef = component}
/>
);
}
render() {
return (
<View ref='container' style={{flex:1}}>
<ListView
enableEmptySections={true}
automaticallyAdjustContentInsets={false}
initialListSize={20}
pageSize={20}
dataSource={this.state.dataSource}
renderRow={this.renderRow}
renderHeader={this.renderFooter}
renderFooter={this.renderLoadEarlier}
renderScrollComponent={this.renderScrollComponent}
{...this.props.listViewProps}
/>
</View>
);
}
}
MessageContainer.defaultProps = {
messages: [],
user: {},
renderFooter: null,
renderMessage: null,
onLoadEarlier: () => {
},
};
MessageContainer.propTypes = {
messages: React.PropTypes.array,
user: React.PropTypes.object,
renderFooter: React.PropTypes.func,
renderMessage: React.PropTypes.func,
onLoadEarlier: React.PropTypes.func,
};