-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Modified for flatlist (from #629) #705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
10b8e6a
33dc31f
1ea1775
8ff8f3a
6786177
e1cc214
c41b64d
43b57fa
d7e8718
761126d
a490305
0fea254
3903cd9
ffb9c8a
5dc7f1a
8abb5a3
4f07992
a85b9fb
75ded90
b2e74d5
5b35d29
05281c3
a7bfd07
32a268d
505d749
8ccbcd0
abbbdbe
a27677d
ad12782
903dabf
b8deab5
321afe4
7cd6d79
58b59d7
75c7442
2412107
7f12e12
5ef003e
e93d2d8
e67f3cc
bebe79f
30d02be
680e4cd
f60bd71
d5f454e
041ffb9
5845c41
a2deae8
ca6f0f5
3eb2ff0
f60f1f2
b55d841
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,17 +3,16 @@ | |
| no-param-reassign: 0, | ||
| no-use-before-define: ["error", { "variables": false }], | ||
| no-return-assign: 0, | ||
| react/no-string-refs: 0 | ||
| react/no-string-refs: 0, | ||
| react/sort-comp: 0 | ||
| */ | ||
|
|
||
| import PropTypes from 'prop-types'; | ||
| import React from 'react'; | ||
|
|
||
| import { ListView, View, StyleSheet } from 'react-native'; | ||
| import { FlatList, View, StyleSheet } 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'; | ||
|
|
||
|
|
@@ -25,30 +24,13 @@ export default class MessageContainer extends React.Component { | |
| 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.renderHeaderWrapper = this.renderHeaderWrapper.bind(this); | ||
| this.keyExtractor = this.keyExtractor.bind(this); | ||
| this.state = { | ||
| dataSource: dataSource.cloneWithRows(messagesData.blob, messagesData.keys), | ||
| messagesData: this.prepareMessages(props.messages), | ||
| }; | ||
| } | ||
|
|
||
| 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), | ||
| }); | ||
| } | ||
|
|
||
| shouldComponentUpdate(nextProps, nextState) { | ||
| if (!shallowequal(this.props, nextProps)) { | ||
| return true; | ||
|
|
@@ -60,26 +42,35 @@ export default class MessageContainer extends React.Component { | |
| } | ||
|
|
||
| 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; | ||
| }, {}), | ||
| }; | ||
| return messages.reduce((o, m, i) => { | ||
| const previousMessage = messages[i + 1] || {}; | ||
| const nextMessage = messages[i - 1] || {}; | ||
| o.push({ | ||
| ...m, | ||
| previousMessage, | ||
| nextMessage, | ||
| }); | ||
| return o; | ||
| }, []); | ||
| } | ||
|
|
||
| scrollTo(options) { | ||
| this._invertibleScrollViewRef.scrollTo(options); | ||
| componentWillReceiveProps(nextProps) { | ||
| if (this.props.messages === nextProps.messages) { | ||
| return; | ||
| } | ||
| this.setState({ | ||
| messagesData: this.prepareMessages(nextProps.messages), | ||
| }); | ||
| } | ||
|
|
||
| renderFooter() { | ||
| if (this.props.renderFooter) { | ||
| const footerProps = { | ||
| ...this.props, | ||
| }; | ||
| return this.props.renderFooter(footerProps); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| renderLoadEarlier() { | ||
|
|
@@ -95,72 +86,66 @@ export default class MessageContainer extends React.Component { | |
| return null; | ||
| } | ||
|
|
||
| renderFooter() { | ||
| if (this.props.renderFooter) { | ||
| const footerProps = { | ||
| ...this.props, | ||
| }; | ||
| return this.props.renderFooter(footerProps); | ||
| } | ||
| return null; | ||
| scrollTo(options) { | ||
| this.refs.flatListRef.scrollToOffset(options); | ||
| } | ||
|
|
||
| renderRow(message) { | ||
| if (!message._id && message._id !== 0) { | ||
| console.warn('GiftedChat: `_id` is missing for message', JSON.stringify(message)); | ||
| renderRow({ item }) { | ||
| if (!item._id && item._id !== 0) { | ||
| console.warn('GiftedChat: `_id` is missing for message', JSON.stringify(item)); | ||
| } | ||
| if (!message.user) { | ||
| if (!message.system) { | ||
| console.warn('GiftedChat: `user` is missing for message', JSON.stringify(message)); | ||
| if (!item.user) { | ||
| if (!item.system) { | ||
| console.warn('GiftedChat: `user` is missing for message', JSON.stringify(item)); | ||
| } | ||
| message.user = {}; | ||
| item.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', | ||
| key: item._id, | ||
| currentMessage: item, | ||
| previousMessage: item.previousMessage, | ||
| nextMessage: item.nextMessage, | ||
| position: item.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; | ||
| return ( | ||
| <InvertibleScrollView | ||
| {...props} | ||
| {...invertibleScrollViewProps} | ||
| ref={(component) => (this._invertibleScrollViewRef = component)} | ||
| /> | ||
| <View style={{ transform: [{ scaleY: -1 }, { perspective: 1280 }] }}> | ||
| <Message {...messageProps} /> | ||
| </View> | ||
| ); | ||
| } | ||
|
|
||
| render() { | ||
| const contentContainerStyle = this.props.inverted | ||
| ? {} | ||
| : styles.notInvertedContentContainerStyle; | ||
| renderHeaderWrapper() { | ||
| return <View style={styles.headerWrapper}>{this.renderLoadEarlier()}</View>; | ||
| } | ||
|
|
||
| keyExtractor(item, index) { | ||
| return `${item._id} ${index}`; | ||
| } | ||
|
|
||
| render() { | ||
| return ( | ||
| <View ref="container" style={styles.container}> | ||
| <ListView | ||
| <FlatList | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this section in line 92-94 for? In our implementation, we have a case where there's no messages but we are currently loading earlier messages. In this case we would like to render the component we pass in through renderLoadEarlier. |
||
| enableEmptySections | ||
| automaticallyAdjustContentInsets={false} | ||
| initialListSize={20} | ||
| pageSize={20} | ||
| ref="flatListRef" | ||
|
||
| keyExtractor={this.keyExtractor} | ||
| {...this.props.listViewProps} | ||
| dataSource={this.state.dataSource} | ||
| contentContainerStyle={contentContainerStyle} | ||
| renderRow={this.renderRow} | ||
| renderHeader={this.props.inverted ? this.renderFooter : this.renderLoadEarlier} | ||
| renderFooter={this.props.inverted ? this.renderLoadEarlier : this.renderFooter} | ||
| renderScrollComponent={this.renderScrollComponent} | ||
| data={this.state.messagesData} | ||
| renderItem={this.renderRow} | ||
| renderHeader={this.renderFooter} | ||
| renderFooter={this.renderLoadEarlier()} | ||
| style={{ transform: [{ scaleY: -1 }, { perspective: 1280 }] }} | ||
|
||
| {...this.props.invertibleScrollViewProps} | ||
| ListFooterComponent={this.renderHeaderWrapper} | ||
| /> | ||
| </View> | ||
| ); | ||
|
|
@@ -172,8 +157,9 @@ const styles = StyleSheet.create({ | |
| container: { | ||
| flex: 1, | ||
| }, | ||
| notInvertedContentContainerStyle: { | ||
| justifyContent: 'flex-end', | ||
| headerWrapper: { | ||
| flex: 1, | ||
| transform: [{ scaleY: -1 }, { perspective: 1280 }], | ||
|
||
| }, | ||
| }); | ||
|
|
||
|
|
@@ -182,7 +168,7 @@ MessageContainer.defaultProps = { | |
| user: {}, | ||
| renderFooter: null, | ||
| renderMessage: null, | ||
| onLoadEarlier: () => { }, | ||
| onLoadEarlier: () => {}, | ||
| inverted: true, | ||
| loadEarlier: false, | ||
| listViewProps: {}, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,21 +9,70 @@ exports[`should render <MessageContainer /> and compare with snapshot 1`] = ` | |
| } | ||
| > | ||
| <RCTScrollView | ||
| ListFooterComponent={[Function]} | ||
| automaticallyAdjustContentInsets={false} | ||
| contentContainerStyle={Object {}} | ||
| dataSource={ | ||
| ListViewDataSource { | ||
| "items": 0, | ||
| } | ||
| } | ||
| data={Array []} | ||
| disableVirtualization={false} | ||
| enableEmptySections={true} | ||
| getItem={[Function]} | ||
| getItemCount={[Function]} | ||
| horizontal={false} | ||
| initialListSize={20} | ||
| initialNumToRender={10} | ||
| keyExtractor={[Function]} | ||
| maxToRenderPerBatch={10} | ||
| numColumns={1} | ||
| onContentSizeChange={[Function]} | ||
| onEndReachedThreshold={2} | ||
| onLayout={[Function]} | ||
| onMomentumScrollEnd={[Function]} | ||
| onScroll={[Function]} | ||
| onScrollBeginDrag={[Function]} | ||
| onScrollEndDrag={[Function]} | ||
| pageSize={20} | ||
| renderFooter={[Function]} | ||
| renderFooter={null} | ||
|
||
| renderHeader={[Function]} | ||
| renderRow={[Function]} | ||
| renderItem={[Function]} | ||
| scrollEventThrottle={50} | ||
| stickyHeaderIndices={Array []} | ||
| style={ | ||
| Object { | ||
| "transform": Array [ | ||
| Object { | ||
| "scaleY": -1, | ||
| }, | ||
| Object { | ||
| "perspective": 1280, | ||
|
||
| }, | ||
| ], | ||
| } | ||
| } | ||
| updateCellsBatchingPeriod={50} | ||
| viewabilityConfigCallbackPairs={Array []} | ||
| windowSize={21} | ||
| > | ||
| <View /> | ||
| <View> | ||
| <View | ||
| onLayout={[Function]} | ||
| style={null} | ||
| > | ||
| <View | ||
| style={ | ||
| Object { | ||
| "flex": 1, | ||
| "transform": Array [ | ||
| Object { | ||
| "scaleY": -1, | ||
| }, | ||
| Object { | ||
| "perspective": 1280, | ||
|
||
| }, | ||
| ], | ||
| } | ||
| } | ||
| /> | ||
| </View> | ||
| </View> | ||
| </RCTScrollView> | ||
| </View> | ||
| `; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this?