我正在用本机生成一个聊天机器人应用程序,并且在显示保存在我的Firebase中的消息时遇到了一些困难。该消息框显示为空。而且,显示三则消息,而我的Firebase中只有一则消息。我正在使用React-Redux进行状态管理,并使用react-native-router-flux进行导航
这是我的Login.js的代码:
import React, {Component} from 'react'
import {View, Text, TouchableOpacity, StatusBar, ImageBackground} from 'react-native'
import {connect} from 'react-redux'
import {login, loginUser} from '../actions'
import {Input, Card, Button, Spinner} from './common'
class Login extends Component {
loginUser() {
const {email, password} = this.props
this.props.loginUser({email, password})
}
renderButton() {
if(this.props.loading) {
return <Spinner size='large' />
}
return (
<Button style={{backgroundColor: '#2D99FC', color: 'white'}}
text='Sign in'
onPress={this.loginUser.bind(this)}
/>
)
}
render() {
return(
<ImageBackground
style={{width: '100%', height: '100%'}}
source={require('../assets/images/bg.jpg')}
>
<StatusBar hidden />
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{fontSize: 25, fontWeight: 'bold', margin: 10}}>Login</Text>
<Text style={{color: 'grey', margin: 10}}>Stay Connected</Text>
<Card>
<Input
placeholder='name@example.com'
iconName='user'
value={this.props.email}
onChangeText={value => this.props.login({prop: 'email', value})}
/>
<Input
placeholder="******"
iconName='lock'
secureTextEntry
value={this.props.password}
onChangeText={value => this.props.login({prop: 'password', value})}
/>
<Text style={{fontSize: 20, color: 'red'}}>
{this.props.error}
</Text>
{this.renderButton()}
<TouchableOpacity>
<Text style={{color:'#2D99FC', fontWeight: 'bold', margin: 10, marginBottom: 30}}>Forgot Password?</Text>
</TouchableOpacity>
<View style={{flexDirection: 'row', margin: 10}}>
<Text>Don't have an account? </Text>
<TouchableOpacity>
<Text style={{color:'#2D99FC', fontWeight: 'bold'}}>Sign Up</Text>
</TouchableOpacity>
</View>
</Card>
</View>
</ImageBackground>
);
}
}
const mapStateToProps = state => {
const {email, password, loading, error} = state.auth
return {email, password, loading, error}
}
export default connect(mapStateToProps, {login, loginUser})(Login)
这是我的AuthAction.js代码:
import {AsyncStorage} from 'react-native'
import firebase from 'firebase'
import {Actions} from 'react-native-router-flux'
import User from '../User'
import {REGISTER, SIGN_UP_USER, SIGN_UP_USER_SUCCESS, SIGN_UP_USER_FAIL, LOGIN, LOGIN_USER, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL, UPDATE_USERS} from './types'
export const register = ({prop, value}) => {
return {
type: REGISTER,
payload: {prop, value}
}
}
export const createUser = ({email, password, conPass, name}) => {
return(dispatch) => {
dispatch({type: SIGN_UP_USER})
if(password !== conPass) {
signupUserFail(dispatch, 'Passwords do not match')
}
else {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => {
signupUserSuccess(dispatch, user)
addData(name, email)
})
.catch(() => signupUserFail(dispatch, 'Authentication Failed'))
}
}
}
const addData = async (name, email) => {
await AsyncStorage.setItem('userName', name)
await AsyncStorage.setItem('userEmail', email)
User.name = name
User.email = email
firebase.database().ref('users/' + User.name).set({name, email})
}
const signupUserSuccess = (dispatch, user) => {
dispatch({
type: SIGN_UP_USER_SUCCESS,
payload: user
})
}
const signupUserFail = (dispatch, error) => {
dispatch({
type: SIGN_UP_USER_FAIL,
payload: error
})
}
export const login = ({prop, value}) => {
return {
type: LOGIN,
payload: {prop, value}
}
}
export const loginUser = ({email, password}) => {
return(dispatch) => {
dispatch({type: LOGIN_USER})
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => loginUserFail(dispatch, 'Authentication Failed'))
}
}
const loginUserSuccess = (dispatch, user) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user
})
firebase.database().ref('users')
.on('child_added', (val) => {
let person = val.val()
person.name = val.key
dispatch({type: UPDATE_USERS, payload: person})
})
Actions.chat()
}
const loginUserFail = (dispatch, error) => {
dispatch({
type: LOGIN_USER_FAIL,
payload: error
})
}
这是我的AuthReducer.js代码:
import {REGISTER, SIGN_UP_USER, SIGN_UP_USER_SUCCESS, SIGN_UP_USER_FAIL, LOGIN, LOGIN_USER, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL, UPDATE_USERS} from '../actions/types'
import User from '../User'
const INITIAL_STATE = {email: '', password: '', conPass: '', loading: false, error: '', user: null, name: '', user: []}
export default (state = INITIAL_STATE, action) => {
console.log(action)
switch(action.type) {
//Registration
case REGISTER:
return {...state, [action.payload.prop]: action.payload.value}
case SIGN_UP_USER:
return {...state, loading: true, error: ''}
case SIGN_UP_USER_SUCCESS:
return {...state, ...INITIAL_STATE, user: action.payload}
case SIGN_UP_USER_FAIL:
return {...state, error: action.payload, password: '', conPass: '', loading: false}
//Login
case LOGIN:
return {...state, [action.payload.prop]: action.payload.value}
case LOGIN_USER:
return {...state, loading: true, error: ''}
case LOGIN_USER_SUCCESS:
return {...state, ...INITIAL_STATE, user: action.payload}
case LOGIN_USER_FAIL:
return {...state, error: action.payload, password: '', loading: false}
case UPDATE_USERS:
User.name = action.payload.name
User.email = action.payload.email
//default
default:
return state
}
}
这是我给Chat.js的代码:
import React, {Component} from 'react'
import {View, SafeAreaView, Text, TextInput, TouchableOpacity, StatusBar, Dimensions, FlatList} from 'react-native'
import {connect} from 'react-redux'
import {messageChanged, sendMessage, messagesListFetch} from '../actions'
import { Header } from './common';
import User from '../User';
class Chat extends Component {
onMessageChange(text) {
this.props.messageChanged(text)
}
sendMessage() {
const {message} = this.props
this.props.sendMessage(message)
}
componentDidMount() {
this.props.messagesListFetch()
}
render() {
return(
<View>
<View>
<StatusBar hidden />
<Header text='Chat with Me' />
</View>
<SafeAreaView>
<FlatList
scrollEnabled
style={{padding: 10, height: Dimensions.get('window').height * 0.8}}
data={this.props.messageList}
renderItem={(item) => {
return(
<View style={{
flexDirection: 'row',
width: '60%',
alignSelf: item[0] === User.name ? 'flex-end' : 'flex-start',
backgroundColor: item[0] === User.name ? '#00897B' : '#7CB342',
borderRadius: 5,
marginBottom: 10
}}>
<Text style={{color: '#FFF', padding: 7, fontSize: 16}}>{item[1]}</Text>
<Text style={{color: '#EEE', padding: 3, fontSize: 12}}>{item[2]}</Text>
</View>
)
}}
keyExtractor={(item, index) => item[0]}
/>
<View style={{flexDirection: 'row', alignItems: 'center', marginHorizontal: 5}}>
<TextInput
style={styles.input}
placeholder='Type a message...'
value={this.props.message}
onChangeText={this.onMessageChange.bind(this)}
/>
<TouchableOpacity onPress={this.sendMessage.bind(this)} style={{paddingBottom: 10, marginLeft: 5}}>
<Text>Send</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</View>
);
}
}
const styles = {
input: {
padding: 10,
borderWidth: 1,
borderColor: '#CCC',
width: '80%',
marginBottom: 10,
borderRadius: 5,
},
}
const mapStateToProps = state => {
let messages = state.chat.messageList
let messageList = []
Object.keys(messages).map((key, index) => {
messageList.push(messages[key])
})
let message = state.chat.message
return {message, messageList}
}
export default connect(mapStateToProps, {messageChanged, sendMessage, messagesListFetch})(Chat)
这是我的ChatActions.js代码:
import firebase from 'firebase'
import {MESSAGE_CHANGED, MESSAGE_SENT, GET_MESSAGE_LIST} from './types'
import User from '../User'
export const messageChanged = (text) => {
return {
type: MESSAGE_CHANGED,
payload: text
}
}
export const sendMessage = (textMessage) => {
return(dispatch) => {
if(textMessage.length > 0) {
console.log(User.name)
let msgId = firebase.database().ref('messages').child(User.name).child('Bot').push().key
let updates = {}
let message = {
message: textMessage,
time: firebase.database.ServerValue.TIMESTAMP,
from: User.name
}
updates['messages/' + User.name + '/' + 'Bot' + '/' + msgId] = message
updates['messages/' + 'Bot' + '/' + User.name + '/' + msgId] = message
firebase.database().ref().update(updates)
dispatch({type: MESSAGE_SENT})
}
}
}
export const messagesListFetch = () => {
return(dispatch) => {
setTimeout(() => {
firebase.database().ref('messages').child(User.name).child('Bot')
.on('child_added', (value) => {
dispatch({type: GET_MESSAGE_LIST, payload: value.val()})
// console.log(value.val())
})
}, 1000)
}
}
这是我的ChatReducer.js代码:
import {MESSAGE_CHANGED, MESSAGE_SENT, GET_MESSAGE_LIST} from '../actions/types'
const INITIAl_STATE = {message: '', messageList: []}
export default (state = INITIAl_STATE, action) => {
switch(action.type) {
case MESSAGE_CHANGED:
return {...state, message: action.payload}
case MESSAGE_SENT:
return {...state, message: ''}
case GET_MESSAGE_LIST:
return {...state, messageList: action.payload}
default:
return state
}
}
Here is my User.js:
User = {
name: '',
email: ''
}
export default User
我希望消息仅显示一次,而不是三次。我怎样才能做到这一点?有人可以帮我吗?