I have a RN app +Meteor App as a backend.
The publishing is set up in Meteor>server>publications:
Meteor.publish('deputies', () => {
return Deputies.find({});
});
The Subscription is set up in RN> DeputiesList
class Deputies_List extends Component{
render(){
const {deputies}= this.props;
return(
<View>
{this.props.deputies.map(deputy=><DeputyDetail deputy={deputy} key={deputy._id}/>)}
</View>
);
}
}
export default createContainer(params=>{
return{
deputies: Meteor.collection('deputies').find({}),
};
},Deputies_List)
Here is the DeputyDetail component:
const DeputyDetail =({deputy})=>{
const{name} = deputy;
return(
<Text>Nom : {name}</Text>
);
}
export default DeputyDetail;
Error: no message, but nothing appears on the screen.
I should have one entry.
Any idea ?
From your code, it doesn't appear that you are subscribing to the deputies publication. I think if you call Meteor.subscribe('deputies') within createContainer you should see your expected data.
Related
I'm new to react native development. And I have created this sample note application using Redux for react native. In this application user must be able to add a note and that note needs to be managed via redux store.
And I have created required action and reducer for adding note functionality.
However I was not able to add a new note to the store. I tried debugging and when it reaches the "ADD_Note" case in reducer, it jump into default case automatically. And whatever the string value or note that pass via action, it becomes 'undefined' in the reducer.
Please refer my code for adding note screen
import React, {useState, useEffect} from 'react';
import {
StyleSheet,
View,
Text,
TextInput,
Button,
FlatList,
} from 'react-native';
import {useSelector, useDispatch} from 'react-redux';
import * as NoteActions from '../store/actions/Note'; // import note actions
const NoteScreen = () => {
const [note, setNote] = useState('');
const dispatch = useDispatch(); // use dispatch
const noteHandler = text => {
setNote(text);
};
return (
<View style={styles.container}>
<View>
<TextInput
style={styles.textInput}
placeholder="Enter a note"
onChangeText={noteHandler}
value={note}
/>
<Button
title="Add"
onPress={() => {
console.log(note);
dispatch(NoteActions.addNote(note));
}}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
width: '100%',
margin: 10,
},
textInput: {
width: '100%',
marginBottom: 10,
textAlign: 'center',
borderBottomWidth: 1,
},
});
export default NoteScreen;
And below is the action js file.
// action types
export const ADD_NOTE = 'ADD_NOTE'
//action creators
export function addNote(note){
return{
type:ADD_NOTE,
date:note
}
}
And below is the reducer js file
// initial state
const initialState ={
noteList:[]
}
// import actions
import ADD_NOTE from '../actions/Note';
function noteReducer (state=initialState, action){
debugger;
switch(action.type){
case ADD_NOTE:
const newNote = action.data
return{
...state,
noteList: state.noteList, newNote
}
default:
return state;
}
}
export default noteReducer;
Please help me.
Thanks in advance,
Yohan
You need to add layer of dispatch at your action, also watch the typo date instead data
export const addNote = (note) => (dispatch, getState) => {
return dispatch({
type:ADD_NOTE,
data :note
})
}
I'm looking at a React-Redux app and try to understand how everything is working.
Inside one of the components, I saw these lines of code:
import { bindActionCreators } from "redux";
...
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchPhotos }, dispatch);
}
export default connect(
null,
mapDispatchToProps
)(SearchBar);
If I change the above code to the following, everything still works, without any errors:
function mapStateToProps(photos) {
return { photos };
}
export default connect(
mapStateToProps,
{ fetchPhotos }
)(SearchBar);
To me, it seems that my way of using connect is easier to understand and it also doesn't need to import an extra library.
Is there any reasons, to import bindActionCreators and use mapDispatchToProps?
I'm a Redux maintainer.
Yes, the second example you showed uses the "object shorthand" form of mapDispatch.
We recommend always using the “object shorthand” form of mapDispatch, unless you have a specific reason to customize the dispatching behavior.
I personally avoid using bindActionCreators explicitly. I prefer to directly dispatch the functions with mapDispatchToProps which internally uses bindActionCreators.
const mapStateToProps = state => ({
photos: state.photos.photos
});
const mapDispatchToProps = dispatch => ({
fetchPhotos: () => dispatch(fetchPhotos())
// ...Other actions from other files
});
export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);
There are two cases in which you'll use bindActionCreators explicitly, both are not best practices:
If you have a child component to SearchBar that does not connect to redux, but you want to pass down action dispatches as props to it, you can use bindActionCreators.
Best practice would be doing same with example I. You can just pass this.props.fetchPhotos to childcomponent directly without using bindActionCreators.
class SearchBar extends React.Component {
render() {
return (
<React.Fragment>
<ChildComponentOfSearchBar fetchPhotos={this.props.fetchPhotos} />
</React.Fragment>
)
}
}
const mapStateToProps = state => ({
photos: state.photos.photos
});
const mapDispatchToProps = () => bindActionCreators({ fetchPhotos }, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);
There is another unlikely scenario where you can use bindActionCreators, defining actionCreator inside the component. This isn't maintainable & is not a good solution since action types are hard coded and not reusable.
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.fetchPhotosAction = bindActionCreators({ fetchPhotos: this.searchFunction }, dispatch);
}
searchFunction = (text) => {
return {
type: ‘SEARCH_ACTION’,
text
}
}
render() {
return (
<React.Fragment>
// Importing selectively
<ChildComponentOfSearchBar fetchPhotos={this.fetchPhotosAction} />
</React.Fragment>
)
}
}
const mapStateToProps = state => ({
photos: state.photos.photos
});
export default connect(mapStateToProps, null)(SearchBar)
Hye guys.. im trying to use react-navigation and firebase in my project.
Im using this awesome boilerplate :-
https://github.com/jhen0409/react-native-boilerplate
in my navigator.js
import { StackNavigator } from 'react-navigation';
import Home from './containers/Home';
import MainScreen from './containers/MainScreen';
import HelpScreen from './containers/HelpScreen';
const AppNavigator = new StackNavigator(
{
Home: { screen: Home },
MainScreen: { screen: MainScreen },
HelpScreen: { screen: HelpScreen }
},
{
headerMode: 'screen'
},
);
export default AppNavigator;
and then in my landing screen which is Home.js
#firebaseConnect()
#connect(
state => ({
nav: state.nav.routes
}),
dispatch => bindActionCreators(userActions, dispatch),
)
export default class Home extends Component {
componentDidMount() {
this.props.firebase.auth().onAuthStateChanged( user => {
if(user) {
//check route stack in redux store
if(this.props.nav[this.props.nav.length-1].routeName !== 'MainScreen') {
this.props.navigation.navigate('MainScreen');
}
this.props.firebase.updateProfile({ lastLogin: new Date() });
user.getIdToken().then( t => this.props.userToken(t) );
} else {
this.props.firebase.auth().signInAnonymously()
.then((user) => {
console.log('user successfully sign in anonymously', user);
// Insert user record to firebase
this.props.firebase.updateProfile(
{
name: 'Anonymous'
}
)
})
.catch(
(error) => {
console.log('error ', error)
})
}
})
}
render() {
return (
<View />
);
}
}
and inside my MainScreen.js
#firebaseConnect(['/helpDetails'])
#connect(
(state, props) => {
return({
})
}
)
export default class MainScreen extends Component {
logout = () => {
this.props.navigation.goBack();
this.props.firebase.logout();
console.log('logout!');
}
render() {
return (
<View style={{ flex: 1 }}>
<TouchableOpacity onPress={() => this.logout()}>
<Text>LOG OUT</Text>
</TouchableOpacity/>
</View>
)
}
}
everything is going fine when user open the apps.. but it start to give this red screen when I click the logout.. if I change firebaseConnect inside Mainscreen from
#firebaseConnect(['/helpDetails'])
TO
#firebaseConnect([])
then everything is working fine..
can anyone help me what im doing wrong here? thanks!
I think this is not a problem of you, but of the library. I have the same issue. Thank god this is only happening while in developer mode (in release everthing works fine).
When I try it without devtools, it works. In my opinion react-redux-firebase is doing some weird stuff when logging out and creates (maybe just for one second) a circular JSON-structure. In JavaScript itself this isn't a big problem, but when you want to stringify it (which is done to display it in your devtools), then the circular structure cannot be converted to a String. Hope to see a fix for that soon from the devs.
Related Issue: Github Issue react-redux-firebase
I am new to React Native and Firebase, this is probably easy but I can't figure out what's wrong. I'm trying to:
(1) Fetch a list of items from my Firebase database, convert the snapshot.val() that Firebase returns into an array (DONE)
(2) Filter that array for when each object has a specific color (DONE)
(3) Send that filtered array of objects to a function that renders a JSX component to the screen (NOT WORKING)
PROBLEM - The console.log above the return() statement in renderItems() tells me that I am getting the data that I need to be there correctly, but for whatever reason, the JSX components are not rendering to the screen. I feel like there is something simple I am missing, but I just can't figure out what. Please help!
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import _ from 'lodash';
import firebase from 'firebase';
import Item from './Item';
class ItemList extends Component {
getItemsByColor(color) {
const itemsRef = firebase.database().ref('/items/');
itemsRef.once('value').then((snapshot) => {
const filteredItems = _.filter(snapshot.val(), item => {
return item.color === color;
});
this.renderItems(filteredItems);
}, (error) => {
// The Promise was rejected.
console.error(error);
});
}
renderItems(filteredItems) {
filteredItems.map((item) => {
console.log(item.name);
return <Item name={item.name} color={item.color} />;
});
}
render() {
return (
<ScrollView style={{ backgroundColor: '#333', flex: 1 }}>
{this.getItemsByColor('blue')}
</ScrollView>
);
}
}
export default ItemList;
Within renderItems() you are returning each <Item/> to the map function, but are not then returning the result of the function afterwards. Try including another return like so:
renderItems(filteredItems) {
return filteredItems.map((item) => {
console.log(item.name);
return <Item name={item.name} color={item.color} />;
});
}
You may need to then put in a couple more return statements in getItemsByColor() as well so that the array of <Item/>'s is returned to the function call within render().
Newbie here trying to learn some Redux.
GOAL: to get a button to click and login/logout, updating the store as true/false status whichever way.
const store = createStore(myReducer)
Created my store, passing in my reducer.
This has a default state of logged out. And returns the opposite, whenever the button is clicked.
I know this action works through debugging.
function myReducer(state = { isLoggedIn: false }, action) {
switch (action.type) {
case 'TOGGLE':
return {
isLoggedIn: !state.isLoggedIn
}
default:
return state
}
}
The problem starts here - when i try to access the store.getState() data.
class Main extends React.Component {
render() {
return (
<div>
<h1>Login Status: { state.isLoggedIn }</h1>
<button onClick={this.props.login}>Login</button>
</div>
)
}
}
const render = () => {
ReactDOM.render(<Main status={store.getState().isLoggedIn} login={() => store.dispatch({ type: 'TOGGLE' })}/>, document.getElementById('root'));
}
store.subscribe(render);
render();
I've tried store.getState().isLoggedIn & store.getState() & this.props.status and then assigning the store.getState().isLoggedIn in the Main component - but nothing works.
Can anyone tell me where i'm going wrong?
You don't directly access the store using getState to find data. The Redux docs explain the process in-depth, but basically you'll connect each component to the Redux store using connect method of the react-redux package.
Here's an example of how this could work for your above component:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Main from '../components/Main'
class MainContainer extends Component {
render() {
return <Main {...this.props} />
}
}
const mapStateToProps = state => ({
isLoggedIn: state.isLoggedIn,
})
const mapDispatchToProps = dispatch => ({
login() {
dispatch({type: 'TOGGLE'})
},
})
MainContainer = connect(
mapStateToProps,
mapDispatchToProps,
)(MainContainer)
export default MainContainer
You would then want to render the MainContainer in place of the Main component. The container will pass down isLoggedIn and login as props to Main when it renders it.