教我自己通过制作聊天应用做出反应,现在当有人点击消息旁边的删除按钮(此代码中不可见,因为它不相关)时,它会从数据库中删除它,但我需要在此处进行更改在应用程序中。
为此,我为每个<Message/>
组件设置了一个ref,并且我有一个与组件上的ref匹配的ref。但我需要定位具有该参考的实际组件节点。
是否有办法实现这一目标?如果没有,我还能做什么?
非常感谢
编辑:完整代码:
import React, { Component } from "react"
import { ListView, View, Text, StyleSheet, TextInput, TouchableHighlight } from "react-native"
import * as firebase from 'firebase';
import Icon from 'react-native-vector-icons/FontAwesome'
import { Hideo } from 'react-native-textinput-effects';
import Message from './Message'
export default class Chat extends Component {
constructor() {
super();
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.onSend = this.onSend.bind(this);
this.state = {
messages: this.ds.cloneWithRows([]),
messageContent: '',
};
}
componentWillMount() {
// Get all of the messages from firebase database and push them into "nodes" array which then gets set in the "messages" state above in handleChat.
const chatRef = firebase.database().ref().child('general');
this.messages = [];
chatRef.on('child_added', snap => {
this.messages.push({user: snap.val().user.name,
text: snap.val().text,
messageId: snap.key
})
this.handleChat(this.messages);
}
).bind(this);
// this is what happens when someone removes a comment
chatRef.on('child_removed', snap => {
const messageId = snap.key; // <- This is the key in the database, for example: '-KVZ_zdbJ0HMNz6lEff'
this.removeMessage(messageId);
})
}
removeMessage(messageId){
let messages = this.messages.filter(message => message.messageId !== messageId);
this.handleChat(messages);
}
handleChat(messages) {
this.setState({messages: this.ds.cloneWithRows(messages)})
}
onSend(messages) {
const generalRef = firebase.database().ref().child('general');
const user = firebase.auth().currentUser;
generalRef.push(
{
_id: 1,
text: this.state.messageContent,
createdAt: new Date().getTime(),
user: {
_id: 2,
name: user.displayName,
avatar: 'http://mdepinet.org/wp-content/uploads/person-placeholder.jpg'
}
});
this.setState({messageContent: ''})
}
removeMessage(messageId){
let messages = this.messages.filter(message => message.messageId !== messageId);
this.handleChat(messages);
}
render() {
return (
<View style={{flex: 1, alignItems: 'flex-end'}}>
<ListView
style={{ marginBottom: 60 }}
enableEmptySections={true}
dataSource={this.state.messages}
renderRow={message => <Message name={message.user} text={message.text}/> }/>
<Hideo
style={{position: 'absolute', bottom: 0}}
onChangeText={messageContent => this.setState({messageContent})} value={this.state.messageContent} placeholder="Name"
iconClass={Icon}
iconName={'envelope'}
iconColor={'white'}
iconBackgroundColor={'#222'}
inputStyle={{ color: '#464949' }}
/>
<TouchableHighlight onPress={this.onSend} style={{position: 'absolute', alignItems: 'center', bottom: 10, right: 10, borderRadius: 10, backgroundColor: '#d4af37'}}>
<Text style={{color: 'whitesmoke', fontSize: 20, padding: 5}}>Send</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
username: {
fontFamily: 'AvenirNext-Bold'
},
comment: {
fontFamily: 'AvenirNext-Regular'
},
bubble: {
flex: 1,
width: 250,
backgroundColor: '#f5f5f5',
margin: 15,
padding: 10,
borderRadius: 20
}
})
答案 0 :(得分:1)
对ListView行项使用refs不是一个好主意。正如Elmeister所说,我们只需要从数组中删除消息元素并更新ListView数据源,以便从ListView中删除消息。
以下是一个示例代码,可让您了解如何在应用中执行相同操作。
import React, {
Component
} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView,
TouchableHighlight,
} from 'react-native';
class StackOverflow extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.messages = this.getMessages();
this.state = {
dataSource: ds.cloneWithRows(this.messages)
};
}
getMessages() {
let arr = [];
for (let i = 0; i < 100; i++) {
arr.push({
user: 'User ' + i,
text: 'This is a sample user message ' + i,
messageId: 'messageId' + i,
});
}
return arr;
}
onDeletePress(messageId) {
this.messages = this.messages.filter(message => message.messageId !== messageId);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.messages)
});
}
renderRow(rowData) {
return (
<View style={{padding:8}}>
<Text>{rowData.user}</Text>
<Text>{rowData.text}</Text>
<TouchableHighlight
style={{alignSelf :'flex-end',backgroundColor:'red'}}
onPress={this.onDeletePress.bind(this,rowData.messageId)}>
<Text>Delete</Text>
</TouchableHighlight>
</View>
);
}
render() {
return (
<View style={{flex: 1, paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
/>
</View>
);
}
}
AppRegistry.registerComponent('StackOverflow', () => StackOverflow);
在上面的示例中,我们正在创建虚拟消息并将其保存在messages
数组中并使用消息更新dataSource
。
调用onDeletePress
后,我们将messageId
传递给该方法,并将其传递到
this.messages = this.messages.filter(message => message.messageId !== messageId);
从messages
数组中删除邮件。然后我们更新将更新ListView的dataSource
状态。
在您的代码中可能需要进行这些更改,
更改handleChat
handleChat(messages) {
this.setState({messages: this.ds.cloneWithRows(messages)})
}
更新聊天组件,如下所示,
import React, {Component} from "react"
import {ListView, View, Text, StyleSheet, TextInput, TouchableHighlight} from "react-native"
import * as firebase from 'firebase';
import Icon from 'react-native-vector-icons/FontAwesome'
import {Hideo} from 'react-native-textinput-effects';
import Message from './Message'
export default class Chat extends Component {
constructor() {
super();
this.chatRef = firebase.database().ref().child('general');
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.onSend = this.onSend.bind(this);
this.state = {
messages: this.ds.cloneWithRows([]),
messageContent: '',
};
}
componentWillMount() {
// Get all of the messages from firebase database and push them into "nodes" array which then gets set in the "messages" state above in updateMessageList.
this._messages = [];
this.chatRef.on('child_added', snap => {
this._messages.push({
user: snap.val().user.name,
text: snap.val().text,
messageId: snap.key
});
this.updateMessageList(this._messages);
}
).bind(this);
// this is what happens when someone removes a comment
this.chatRef.on('child_removed', snap => {
const messageId = snap.key; // <- This is the key in the database, for example: '-KVZ_zdbJ0HMNz6lEff'
this.removeMessage(messageId);
}).bind(this);
}
removeMessage(messageId) {
this._messages = this._messages.filter(message => message.messageId !== messageId);
this.updateMessageList(this._messages);
}
updateMessageList(messages) {
this.setState({messages: this.ds.cloneWithRows(messages)})
}
onSend(messages) {
const user = firebase.auth().currentUser;
this.chatRef.push(
{
_id: 1,
text: this.state.messageContent,
createdAt: new Date().getTime(),
user: {
_id: 2,
name: user.displayName,
avatar: 'http://mdepinet.org/wp-content/uploads/person-placeholder.jpg'
}
});
this.setState({messageContent: ''})
}
render() {
return (
<View style={{flex: 1, alignItems: 'flex-end'}}>
<ListView
style={{ marginBottom: 60 }}
enableEmptySections={true}
dataSource={this.state.messages}
renderRow={message => <Message name={message.user} text={message.text}/> }/>
<Hideo
style={{position: 'absolute', bottom: 0}}
onChangeText={messageContent => this.setState({messageContent})} value={this.state.messageContent}
placeholder="Name"
iconClass={Icon}
iconName={'envelope'}
iconColor={'white'}
iconBackgroundColor={'#222'}
inputStyle={{ color: '#464949' }}
/>
<TouchableHighlight onPress={this.onSend}
style={{position: 'absolute', alignItems: 'center', bottom: 10, right: 10, borderRadius: 10, backgroundColor: '#d4af37'}}>
<Text style={{color: 'whitesmoke', fontSize: 20, padding: 5}}>Send</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
username: {
fontFamily: 'AvenirNext-Bold'
},
comment: {
fontFamily: 'AvenirNext-Regular'
},
bubble: {
flex: 1,
width: 250,
backgroundColor: '#f5f5f5',
margin: 15,
padding: 10,
borderRadius: 20
}
});