I am using redux to store and fetch my data from Firebase. The data is stored successfully, however, the view MyActivities is not updated with the new data. Am I doing something wrong here ?
I need to rerender the whole application for the views to be updated with the new data stored in Firebase.
I didn't add all the code used in this example.
ActivitiesAction.js
import firebase from 'firebase';
import { Navigation } from 'react-native-navigation';
import {
ACTIVITIES_FETCH_SUCCESS,
ACTIVITIES_SEND_SUCCESS,
SUBACTIVITY_SEND_SUCCESS
} from './types';
export const activitiesFetch = () => {
return (dispatch) => {
firebase.database().ref('users_data/s80GnOQu22W4XLLYbuKUBC2BzkY2/').once('value')
.then((snapshot) => {
dispatch({
type: ACTIVITIES_FETCH_SUCCESS,
payload: snapshot.val()
});
});
};
};
export const activitiesSend = (activityDescription,
activityDate, category, notification, alarm) => {
const ref = firebase.database()
.ref('users_data/s80GnOQu22W4XLLYbuKUBC2BzkY2/activities/cheduled_activities');
const activity = ref.push();
const ref2 = firebase.database()
.ref('users_data/s80GnOQu22W4XLLYbuKUBC2BzkY2/activities/all_activities');
const activityList = ref2.push();
return (dispatch) => {
activity.set({
activityDescription,
activityDate,
category,
// time: this.state.time,
notification,
alarm
}).then(activityCreated => {
dispatch({ type: ACTIVITIES_SEND_SUCCESS, payload: activityCreated });
activityList.set({
activityDescription,
category
}).then(listActivity => {
dispatch({ type: SUBACTIVITY_SEND_SUCCESS, payload: listActivity });
});
});
};
};
ActivitiesReducer.js
import {
ACTIVITIES_FETCH_SUCCESS,
ACTIVITIES_SEND_SUCCESS,
SUBACTIVITY_SEND_SUCCESS
} from '../actions/types';
const INITIAL_STATE = { activitiesData: '', activityCreated: null, listActivity: null };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ACTIVITIES_FETCH_SUCCESS:
return { ...state, activitiesData: action.payload };
case ACTIVITIES_SEND_SUCCESS:
return { ...state, activityCreated: action.payload };
case SUBACTIVITY_SEND_SUCCESS:
return { ...state, listActivity: action.payload };
default:
return state;
}
};
MyActivities.js
import React, { Component } from 'react';
import { Container, Content, View } from 'native-base';
import { connect } from 'react-redux';
import _ from 'lodash';
import { activitiesFetch } from '../actions/ActivitiesAction';
import Activity from './Activity';
class MyActivities extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.activitiesFetch();
}
componentWillReceiveProps(nextProps) {
this.setState({ activitiesData: nextProps });
console.log('next props:', nextProps);
}
componentWillUpdate(nextProps, nextState) {
console.log('next props:', nextProps);
}
renderActivities() {
// this.setState({ data: this.props.activitiesArray });
console.log('acti():', this.props.activitiesData);
const activitiesArray = _.values(this.props.activitiesData);
console.log('acti[]:', activitiesArray);
const list = _.values(activitiesArray[0]) || [];
const act = list.map((activities) => (activities));
console.log('acti[]:', act);
const activities = _.values(act[1]);
return (
activities.map((singleActivity, i) => (
<Activity
key={i}
Title={singleActivity.activityDescription}
Author={activitiesArray[1].full_name}
Time={singleActivity.time}
PeopleStats={'0'}
/>
))
);
}
render() {
return (
<Container>
{/* <HeaderActivities /> */}
<Content style={styles.Content}>
{/* <ScrollView style={{ flex: 1 }}> */}
<View style={styles.styleView}>
{this.renderActivities()}
</View>
{/* </ScrollView> */}
</Content>
</Container>
);
}
}
const mapStateToProps = state => {
return {
// activitiesArray: _.values(state.activitiesData)
activitiesData: state.activitiesData
};
};
const styles = {
Content: {
backgroundColor: '#F0F5F7',
},
styleView: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center',
// alignItems: 'flex-start',
// alignContent: 'flex-start'
},
ButtonActive: {
borderBottomColor: '#FF8600',
borderBottomWidth: 3,
paddingBottom: 3,
borderRadius: 0
}
};
export default connect(mapStateToProps, { activitiesFetch })(MyActivities);
Use the redux and react dev tools to check
did the expected action dispatch?
does the state change match your expectations?
do components have the props you expect them to have?
Related
I'm building a React Native app, currently trying to implement an authentication registration system through Firebase. here is my whole code.
import React, { Component } from 'react';
import { Platform, StyleSheet, KeyboardAvoidingView, SafeAreaView, View, YellowBox, LogBox, AsyncStorage } from 'react-native';
import { GiftedChat, InputToolbar } from 'react-native-gifted-chat';
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
import AnimatedLoader from "react-native-animated-loader";
import firebaseSDK from "../../firebaseSDK";
import firebase from 'firebase';
import { v4 as uuid } from 'uuid';
LogBox.ignoreLogs(['Setting a timer']);
const customtInputToolbar = props => {
return (
<InputToolbar
{...props}
containerStyle={{
backgroundColor: "white",
borderTopColor: "#E8E8E8",
borderTopWidth: 1,
//padding: 8
}}
/>
);
};
export default class Chat extends Component {
constructor(props) {
super(props);
this.state = {
messages: [],
chatgenidres: '',
}
this.init()
this.checkAuth()
}
init = () => {
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: "xxxxxxxxxxxxxxxxxxxxxs",
authDomain: "xxxxxxxxxxxxx",
databaseURL: "xxxxxxxxxxxxxxxxxxxx",
projectId: "xxxxxxxxxxx",
storageBucket: "xxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxx",
measurementId: "xxxxxxxxxxxxx"
})
}
};
checkAuth = () => {
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously();
}
})
}
send = messages => {
console.log(messages);
messages.forEach(item => {
const message = {
text: item.text,
timestamp: firebase.database.ServerValue.TIMESTAMP,
user: item.user
};
this.db.push(message);
});
};
parse = message => {
const { user, text, timestamp } = message.val();
const { key: _id } = message;
const createdAt = new Date(timestamp);
return {
_id,
createdAt,
text,
user
};
};
get = callback => {
this.db.on("child_added", snapshot => callback(this.parse(snapshot)));
};
off() {
this.db.off();
}
get db() {
console.log(this.state.chatgenidres)
return firebase.database().ref(this.state.chatgenidres)
};
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get user() {
return {
_id: this.uid,
chatfromusername: this.props.navigation.state.params.chatFromName,
chatfromuserid: this.props.navigation.state.params.chatFromId,
chattouserid: this.props.navigation.state.params.chatToId,
chattousername: this.props.navigation.state.params.chatToName,
}
}
componentDidMount() {
let genId = this.props.navigation.state.params.chatFromId + 'connectedto' + this.props.navigation.state.params.chatToId;
//AsyncStorage.setItem('chatgenid', genId);
AsyncStorage.getItem('chatgenid', (err, chatgenidres) => {
console.log(chatgenidres, 'from chat.js');
this.setState({ chatgenidres: chatgenidres });
this.get(message =>
this.setState(previous => ({
messages: GiftedChat.append(previous.messages, message)
}))
);
});
}
componentWillUnmount() {
this.off();
}
render() {
const chat = <GiftedChat
messages={this.state.messages}
onSend={this.send}
user={this.user}
style={styles.messageContainer}
renderInputToolbar={props => customtInputToolbar(props)}
/>;
if (Platform.OS === 'android') {
return (
<View style={styles.container} behavior="padding" keyboardVerticalOffset={30} enabled>
<View style={{ flexDirection: 'row', padding: 13, justifyContent: 'space-between', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.1)' }}>
<FontAwesomeIcon name="arrow-left" size={20} onPress={() => { this.props.navigation.goBack() }} color="#FFF" />
</View>
{chat}
</View>
)
}
return <SafeAreaView style={{ flex: 1 }}>{chat}</SafeAreaView>
}
}
but when i run this application i get " FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app)." this error.what is wrong with my code.how to solve this.
If 2 user is using the app, messages are being displayed on the left side of the screen. cannot differentiate between them
here my full code below
import React, { Component } from 'react';
import { Platform, StyleSheet, KeyboardAvoidingView, SafeAreaView, View, YellowBox, LogBox, AsyncStorage } from 'react-native';
import { GiftedChat, InputToolbar } from 'react-native-gifted-chat';
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
import AnimatedLoader from "react-native-animated-loader";
import firebaseSDK from "../../firebaseSDK";
import firebase from 'firebase';
LogBox.ignoreLogs(['Setting a timer']);
const customtInputToolbar = props => {
return (
<InputToolbar
{...props}
containerStyle={{
backgroundColor: "white",
borderTopColor: "#E8E8E8",
borderTopWidth: 1,
//padding: 8
}}
/>
);
};
export default class Chat extends Component {
constructor(props) {
super(props);
this.state = {
messages: [],
chatgenidres: '',
}
this.init()
this.checkAuth()
}
init = () => {
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: "apiKey",
authDomain: "authDomain",
databaseURL: "databaseURL",
projectId: "projectId",
storageBucket: "storageBucket",
messagingSenderId: "messagingSenderId",
appId: "appId",
measurementId: "measurementId"
})
}
};
checkAuth = () => {
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously();
}
})
}
send = messages => {
console.log(messages);
messages.forEach(item => {
const message = {
text: item.text,
timestamp: firebase.database.ServerValue.TIMESTAMP,
user: item.user
};
this.db.push(message);
});
};
parse = message => {
const { user, text, timestamp } = message.val();
const { key: _id } = message;
const createdAt = new Date(timestamp);
return {
_id,
createdAt,
text,
user
};
};
get = callback => {
this.db.on("child_added", snapshot => callback(this.parse(snapshot)));
};
off() {
this.db.off();
}
get db() {
console.log(this.state.chatgenidres)
return firebase.database().ref(this.state.chatgenidres)
};
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get user() {
return {
_id: this.uid,
chatfromusername: this.props.navigation.state.params.chatFromName,
chatfromuserid: this.props.navigation.state.params.chatFromId,
chattouserid: this.props.navigation.state.params.chatToId,
chattousername: this.props.navigation.state.params.chatToName,
}
}
componentDidMount() {
let genId = this.props.navigation.state.params.chatFromId + 'connectedto' + this.props.navigation.state.params.chatToId;
//AsyncStorage.setItem('chatgenid', genId);
AsyncStorage.getItem('chatgenid', (err, chatgenidres) => {
console.log(chatgenidres, 'from chat.js');
this.setState({ chatgenidres: chatgenidres });
this.get(message =>
this.setState(previous => ({
messages: GiftedChat.append(previous.messages, message)
}))
);
});
}
componentWillUnmount() {
this.off();
}
render() {
const chat = <GiftedChat
messages={this.state.messages}
onSend={this.send}
user={this.user}
style={styles.messageContainer}
renderInputToolbar={props => customtInputToolbar(props)}
/>;
if (Platform.OS === 'android') {
return (
<View style={styles.container} behavior="padding" keyboardVerticalOffset={30} enabled>
<View style={{ flexDirection: 'row', padding: 13, justifyContent: 'space-between', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.1)' }}>
<FontAwesomeIcon name="arrow-left" size={20} onPress={() => { this.props.navigation.goBack() }} color="#FFF" />
</View>
{chat}
</View>
)
}
return <SafeAreaView style={{ flex: 1 }}>{chat}</SafeAreaView>
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#5e5e5e'
},
messageContainer: {
color: 'red'
}
})
But when send one new message at that time message will display separately sender and receiver format. how to differentiate those messages. I use react-native-gifted-chat. but not working properly. I am using react-native-gifted-chat and firebase.
I imported a SearchBar from react-native-elements and I want to be able to search my articles by title. So the field I should be able to pull and search from Cloud Firestore is called 'title'. I'm not sure how to do that.
import React, { Component } from "react";
import { StyleSheet, View, FlatList } from "react-native";
import { AppleCard } from "react-native-apple-card-views";
import firebase from "../../Firebase";
import { SearchBar } from 'react-native-elements';
import { ScrollView } from "react-native-gesture-handler";
export default class Discover extends Component {
constructor(props) {
super();
this.ref = firebase.firestore().collection("articles").where("publish", "==", true);
this.unsubscribe = null;
this.state = {
articles: [],
search: '',
};
}
onCollectionUpdate = (querySnapshot) => {
const articles = [];
querySnapshot.forEach((doc) => {
const { title, subtitle, imageUrlPath } = doc.data();
articles.push({
key: doc.id,
doc, // DocumentSnapshot
title,
subtitle,
imageUrlPath,
});
});
this.setState({
articles,
});
};
componentDidMount() {
this.unsubscribe = this.ref.onSnapshot(this.onCollectionUpdate);
}
updateSearch = (search) => {
this.setState({ search });
};
renderItem = ({ item }) => {
return (
<View>
<View style={styles.card}>
<AppleCard
largeTitle={item.title}
smallTitle=""
footnoteText={item.subtitle}
resizeMode="cover"
source={{uri:item.imageUrlPath}}
onPress={() => {
this.props.navigation.navigate("Content", {
articlekey: `${JSON.stringify(item.key)}`,
});
}}
/>
</View>
</View>
);
};
render() {
const { search } = this.state;
return (
<ScrollView>
<SearchBar
placeholder="Search here..."
onChangeText={this.updateSearch}
value={search}
platform='ios'
/>
<View style={styles.discover}>
<FlatList data={this.state.articles} renderItem={this.renderItem} />
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
discover: {
flex: 1,
backgroundColor: "#FBFCFC",
alignItems: "center",
justifyContent: "center",
},
card: {
padding: 15,
},
});
I am using React Native, Rematch for Redux and Firebase Firestore. I am attempting to pull data from my Firebase database and populate it inside my FlatList. The problem is, it is not giving me any error and it giving me a blank white screen. I do not know where I am going wrong.
This is what my database looks like - list of activities
This is what my Rematch for Redux store looks like:
import firebase from 'firebase';
import db from '../config/firebase'
const activity = {
state: {},
reducers: {
activities(state, payload) {
return {
...state,
...payload
}
},
},
effects: {
async getActivities() {
try {
const response = await db.collection('activities').get()
//console.log(response.docs.map(doc => doc.data()))
return dispatch({ type: 'activity/activities', payload: response.docs.map(doc => doc.data()) })
} catch (err) {
alert(err)
}
},
}
}
export default activity
Here is the component where I am using the FlatList:
import * as React from 'react';
import {
Text,
TouchableOpacity,
View,
FlatList,
ImageBackground
}
from 'react-native';
import styles from '../styles'
import { connect } from 'react-redux';
import '#expo/vector-icons';
import 'redux';
class Activities extends React.Component {
state = {
movetoArray: [],
outputActivity: [],
};
async componentDidMount() {
const activities = await this.props.getActivities()
this.state.movetoArray = Object.values(activities)
this.state.outputActivity = Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] }));
//this.state.arrayActivity = Object.entries(activities).map(item => ({...item[1], key: item[0]}));
console.log(this.state.outputActivity)
}
_renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('activitiesMD',
{
title: item.name,
objectData: item.data
})}>
<ImageBackground source={item.image} style={styles.inputTiles} imageStyle={{ borderRadius: 10 }}>
<View style={styles.inputTileTextView}>
<Text style={[styles.inputTileText, { color: item.colour }]}>{item.name}</Text>
</View>
</ImageBackground>
</TouchableOpacity>
);
render() {
const { routeName } = this.props.navigation.state
return (
<View style={styles.container}>
<FlatList
data={this.state.outputActivity}
keyExtractor={item => item.id}
renderItem={this._renderItem}
/>
</View>
);
}
}
const mapState = (state) => ({
activity: state.activity,
})
const mapDispatch = (dispatch) => ({
getActivities: () => dispatch.activity.getActivities(),
})
export default connect(mapState, mapDispatch)(Activities)
I do not know why I am getting this outcome. Please help me :)
If you directly mutate state in React then the component won't re-render. Please use this.setState({ ... }) like so:
- this.state.movetoArray = Object.values(activities)
- this.state.outputActivity = Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] }));
+ this.setState({ movetoArray: Object.values(activities), outputActivity: Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] })) })
How to declare an array on a state variable
Im using react native expo and firebase all is up to date
export default class Profile extends Component {
state = {
ageRangeValues: this.props.user.ageRange,
distanceValue: [this.props.user.distance],
}
render() {
const {
ageRangeValues,
distanceValue,
} = this.state;
return (
<View>
<Slider
min={5}
max={100}
values={distanceValue}
onValuesChange={val => this.setState({ distanceValue: val })}
onValuesChangeFinish={val => this.updateUser('distance', val[0])}
/>
<Slider
min={18}
max={70}
values={ageRangeValues}
onValuesChange={val => this.setState({ ageRangeValues: val })}
onValuesChangeFinish={val => this.updateUser('ageRange', val)}
/>
</View>) }
I expect this to work fine but the ageRangeValue is undefined but the distanceValue in defined don't know why may be is because ageRangeValue takes ageRange and its an Array. If I declare areRangeValue: [19, 20], everything works, but if I left it the way it is all my values are undefined
and here is my preload
const firebaseConfig = {
apiKey: 'XXXXXXXXX',
databaseURL: 'XXXXX',
storageBucket: 'XXXXX',
};
firebase.initializeApp(firebaseConfig);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
width: null,
height: null,
resizeMode: 'contain',
},
});
export default class Preload extends Component {
constructor() {
super();
this.loadApp();
// SVGAnimatedLengthList.loadApp();
}
authenticate = (token) => {
const provider = firebase.auth.FacebookAuthProvider
const credential = provider.credential(token);
return firebase.auth().signInWithCredential(credential);
};
_goHome = (user) => {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Home', params: { user } })],
});
this.props.navigation.dispatch(resetAction);
};
loadApp = async () => {
//firebase.auth().signOut();
firebase.auth().onAuthStateChanged((auth) => {
if (auth) {
this.firebaseRef = firebase.database().ref('users');
this.firebaseRef.child(auth.uid).on('value', (snap) => {
const user = firebase.auth().currentUser;
if (user != null) {
this.firebaseRef.child(auth.uid).off('value');
this._goHome(user);
}
});
} else {
this.setState({ showSpinner: false });
this.props.navigation.navigate('Login');
}
});
}
render() {
return (
<ImageBackground source={require('./images/fondo.png')} style={styles.container}>
<ActivityIndicator />
</ImageBackground>
);
}
}
Try it with constructor
export default class Profile extends Component {
constructor(){
super();
this.state = {
ageRangeValues: this.props.user.ageRange,
distanceValue: [this.props.user.distance],
};
}
render() {
const { ageRangeValues, distanceValue } = this.state;
return (
<View>
<Slider
min={5}
max={100}
values={distanceValue}
onValuesChange={val => this.setState({ distanceValue: val })}
onValuesChangeFinish={val => this.updateUser('distance', val[0])}
/>
<Slider
min={18}
max={70}
values={ageRangeValues}
onValuesChange={val => this.setState({ ageRangeValues: val })}
onValuesChangeFinish={val => this.updateUser('ageRange', val)}
/>
</View>
);
}
Vencovsky was right on the previews page that pass the data
loadApp = async () => {
//firebase.auth().signOut();
firebase.auth().onAuthStateChanged((auth) => {
if (auth) {
this.firebaseRef = firebase.database().ref('users');
this.firebaseRef.child(auth.uid).on('value', (snap) => {
const user = firebase.auth().currentUser;
if (user != null) {
this.firebaseRef.child(auth.uid).off('value');
this._goHome(user);
}
});
} else {
this.setState({ showSpinner: false });
this.props.navigation.navigate('Login');
}
});
}
Changing const user = firebase.auth().currentUser; to const user = snap.val();
made the trick