I'm playing with react-native / redux and am dispatching an action that is supposed to display a number yet an error gets thrown:
Unhandled JS Exception: Objects are not valid as a React child (found:
object with keys {type, payload}). If you meant to render a collection
of children, use an array instead or wrap the object using
createFragment(object) from the React add-ons. Check the render method
of Text.
createStore.js
import { createStore, applyMiddleware, combineReducers } from 'redux';
import createLogger from 'redux-logger';
import numReducer from './reducers/numReducer';
const logger = createLogger();
export default (initialState = {}) => (
createStore(
combineReducers({
numbers: numReducer
}),
initialState,
applyMiddleware(logger)
)
);
App.js
import React from 'react';
import { Provider } from 'react-redux';
import HomeScreen from './components/HomeScreen';
import createStore from './createStore';
const store = createStore();
export default () => (
<Provider store={store}>
<HomeScreen />
</Provider>
);
numReducer.js
import { LIST_NUMBERS, PICK_NUMBER } from '../actions/actionTypes';
export default (state = [], action = {}) => {
switch (action.type) {
case LIST_NUMBERS:
return action.payload || [];
case PICK_NUMBER:
return action.payload;
default:
return state;
}
};
HomeScreen.js
import React from 'react';
import { View } from 'react-native';
import NavContainer from '../containers/NavContainer';
const HomeScreen = () => (
<View>
<NavContainer />
</View>
);
export default HomeScreen;
NavContainer.js
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { listNumbers, pickNumber } from '../actions/numberActions';
import Nav from '../components/Nav';
const mapStateToProps = state => ({
numbers: state.numbers
});
const mapDispatchToProps = dispatch => (
bindActionCreators({
listNumbers,
pickNumber
}, dispatch)
);
export default connect(
mapStateToProps,
mapDispatchToProps
)(Nav);
Nav.js
import React, { Component, PropTypes } from 'react';
import { View, Text } from 'react-native';
export default class Nav extends Component {
render() {
return (
<View>
<Text>FirstLine</Text>
<Text>SecondLind</Text>
<Text>Number: {this.props.pickNumber(3)}</Text>
</View>
);
}
}
Please advise what I am doing wrong. Thank you
You need to dispatch your action from inside one of your lifecycle methods or on some handler, and then use the (updated) props from your redux store in your component.
Example:
import React, { Component, PropTypes } from 'react';
import { View, Text } from 'react-native';
export default class Nav extends Component {
componentDidMount() {
this.props.pickNumber(3);
}
render() {
return (
<View>
<Text>FirstLine</Text>
<Text>SecondLind</Text>
<Text>Number: {this.props.numbers}</Text>
</View>
);
}
}
Related
I am trying to set up react redux, also i have set it but I am getting an error TypeError: _this.props.showLoader is not a function. (In '_this.props.showLoader(true)', '_this.props.showLoader' is undefined).
this.props.showLoader(true)
This function has been defined in Action.js file you can find it below.
This error comes whenever I try to call a function from Root.js file, you can find it below.
Below is the code what I have done so far:->
I have App.js file in which I have set for provider and store
import React, { Component } from 'react';
import {StyleSheet, View, Text} from 'react-native';
import {Provider} from 'react-redux';
import store from './src/redux/Store'
import Root from './src/root/Root'
function App() {
return (
<Provider store={store}>
<View style={localStyles.container}>
<Root/>
</View>
</Provider>
);
}
export default App;
const localStyles = StyleSheet.create({
container: {
flex: 1,
},
});
This is the Navigation Route File
import React from 'react'
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import TutorialSwipeScreen from '../components/viewcontrollers/onboarding/TutorialSwipeScreen'
const Stack = createStackNavigator();
function goStack() {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false
}}
>
<Stack.Screen name="Login" component={Login Screen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default goStack;
My Root.js file
where I am trying to this.props.showLoader it gives me error
import React, {Component} from 'react'
import {View, StyleSheet, Text} from 'react-native'
import NavigationRoute from './NavigationRoutes'
import DeviceInfo from 'react-native-device-info'
class Root extends Component {
constructor(props) {
super(props)
console.warn('props=', this.props)
}
componentDidMount() {
this.call()
}
call = () => {
this.props.showLoader(true)
}
render () {
return (
<View style={styles.rootContainer}>
<NavigationRoute/>
</View>
)
}
}
export default Root;
const styles = StyleSheet.create({
rootContainer: {
flex: 1,
}
});
My RootContainer.js File
import {bindActionCreators} from 'redux'
import {connect} from 'react-redux'
import * as Actions from '../redux/Actions'
import Root from './Root'
function mapStateToProps(state) {
return {
shouldShowLoader: state.dataReducer._showLoader,
shouldChangeCounting: state.dataReducer.counter
}
}
function mapDispatchToProps(dispatch) {
const mergedActions = Object.assign({}, Actions);
return bindActionCreators(mergedActions, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Root);
My Store.js file
import {createStore} from 'redux'
import reducers from './RootReducer'
export default createStore(reducers);
My RootReducer.js
import {combineReducers} from 'redux'
import dataReducer from './reducers/Reducer'
const rootReducer = combineReducers ({
dataReducer,
})
export default rootReducer;
My Action.js file which has a function showLoader(bool) which I try to call from Root.js which gives me an error as I have quoted above.
export const DISPLAY_LOADER = 'DISPLAY_LOADER';
export const REFRESH = 'REFRESH';
export const COUNTER = 'COUNTER';
export function showLoader(bool) {
return {
type: DISPLAY_LOADER, data: bool,
};
}
export function refresh() {
return {
type: REFRESH, data: true,
};
}
export function counting(count) {
return {
type: COUNTER, data: count
}
}
And Finally Reducer.js file code goes here
import { DISPLAY_LOADER, REFRESH, WELCOME_POPUP, LOGIN_RELOAD, MESSAGE_POPUP, LOGOUT, COUNTER} from '../Actions';
const initialState = {
counter: 5,
_showLoader: false,
_showMessagePopup: false,
_loginReload: false,
_refresh: false,
_heading: 'Message Heading',
_message: 'PWG Custom Message',
}
const dataReducer = (state = initialState, action) => {
switch(action.type) {
case DISPLAY_LOADER: {
return {...initialState, _showLoader: action.data}
}
case REFRESH: {
return {...initialState, _refresh: action.data}
}
case LOGOUT: {
return {...initialState, _refresh: true}
}
case COUNTER: {
return {...initialState, counter: action.data}
}
default: {
return state;
}
}
}
export default dataReducer;
So where my mistake is I am not able to find with what lines of code I am receiving error at my end. Please help. Also I am new to react native please bear with me.
Thanks
I have got the answer, I am answering my own post.
In the App.js File You need to import
RootContainer
instead of
Root
That’s it and it works Voila.
import RootContainer from './src/root/RootContainer'
I see that your showLoader tied to your redux reducer.
what i can suggest you, you should return state not initialState in your reducer. Basically what youre doing is after each change of state in redux, everything else will go back to its initialState but not the changed state itself.
You also didn't pass props showLoader to your Root component. If your intention is using showLoader as a setState function for your Root component, you should define the function in your mapDispatchToProps in your connect function
I try to test redux. I have component Main that redirects to TestRedux. TestRedux componenent make a dispatch and redirects to TestRedux2 when click on a button.
TestRedux and TestRedux2 are the same, I have made a copy/paste, just change values. TestRedux dispatch correctly, but testRedux2 trigger an error.
Do you know what is the cause of the problem ?
// TestRedux
import React from 'react';
import { View, Text, Button, Alert } from 'react-native';
import { ADD_RES } from "../Constants/action-types";
import {addResa} from "../Actions/actions";
import { connect } from 'react-redux'
import Store from '../Store/store'
const mapStateToProps = state => ({ date: state.date })
export class TestRedux extends React.Component {
render() {
this.props.dispatch(addResa(1));
return (
<View>
<Button
onPress={() => { this.props.navigation.navigate('TestRedux2') }}
title='test'
/>
</View>
)
}
}
export default connect(mapStateToProps)(TestRedux)
// TestRedux2
import React from 'react';
import { View, Text, Button, Alert } from 'react-native';
import { ADD_RES } from "../Constants/action-types";
import {addResa} from "../Actions/actions";
import { connect } from 'react-redux'
import Store from '../Store/store'
const mapStateToProps = state => ({ date: state.date })
export class TestRedux2 extends React.Component {
render() {
this.props.dispatch(addResa(2));
return (
<View>
<Button
onPress={() => { this.props.navigation.navigate('TestRedux') }}
title='test2'
/>
</View>
)
}
}
export default connect(mapStateToProps)(TestRedux2)
Store is:
import { createStore } from "redux"; // without redux persist
import { persistCombineReducers } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import resaReducer from "../Reducers/resaReducer";
const rootPersistConfig = {
key: 'root',
storage: storage
}
const Store = createStore(persistCombineReducers(rootPersistConfig, {resaReducer}))
export default Store;
````
Dispatch an action or pass null to connect. See if the issue continues.
export default connect(mapStateToProps)(TestRedux2)
to
export default connect(mapStateToProps, null)(TestRedux2)
I want to test Redux on my react-native app. I navigate through several Components - I want a component TestRedux updates a value and that another component TestRedux2 see this value using Redux.
I followed several tutorials on Redux and did this:
Actions:
//myApp/redux/Actions/action.js
import { ADD_RES } from "../Constants/action-types";
export function addResa(payload) {
return { type: ADD_RES, payload: payload };
}
Constants:
//myApp/redux/Components/action-types.js
export const ADD_RES = "ADD_RES";
export const DEL_RES = "DEL_RES";
Reducers:
//myApp/redux/Reducers/resaReducer.js
import { ADD_RES } from "../Constants/action-types";
const initialState = {
res: []
};
function resaReducer(state = initialState, action) {
let nextState;
switch (action.type) {
case ADD_RES:
nextState = {
...state,
payload: action.payload
}
return nextState;
default:
return state
}
}
export default resaReducer;
Store:
//myApp/redux/Store/store.js
import { createStore } from "redux";
import resaReducer from "../Reducers/resaReducer";
const Store = createStore(resaReducer);
export default Store;
TestRedux:
//myApp/redux/Components/TestRedux.js
// I use react-navigation to navigate between components. The component App is the first component and then trigger to testRedux
import React from 'react';
import { View, Text, Alert } from 'react-native';
import { ADD_RES } from "../Constants/action-types";
import {addResa} from "../Actions/actions";
import { connect } from 'react-redux'
import { Provider } from 'react-redux'
import Store from '../Store/store'
import App from '../../App';
const mapStateToProps = (state) => {
return state.date
}
export class TestRedux extends React.Component {
render() {
this.props.dispatch(addResa(2));
return (
<View>
<Button
onPress={() => {this.props.navigation.navigate('TestRedux2')}}
title='test'
/>
<Provider store={Store}>
<App/>
</Provider>
</View>
)
}
}
export default connect(mapStateToProps)(TestRedux)
TestRedux2:
//myApp/redux/Components/TestRedux2.js
import { connect } from 'react-redux'
import React from 'react';
import { View, Text, Button, Alert } from 'react-native';
import { ADD_RES } from "../Constants/action-types";
import {addResa} from "../Actions/actions";
import Store from '../Store/store'
const mapStateToProps = (state) => {
return state.date
}
export class TestRedux2 extends React.Component {
render() {
console.log("Value from TestRedux2 is", Store.getState())
return (
<View>
<Text> Hello </Text>
</View>
)
}
}
export default connect(mapStateToProps)(TestRedux2)
Do I use correctly Redux ?
I have the following error: “Invariant Violation: Could not find "store" in the context of "Connect(TestRedux)". Either wrap the root component in a , or pass a custom React context provider to and the corresponding React context consumer to Connect(TestRedux) in connect options.”
This code:
<Provider store={Store}>
<App/>
</Provider>
which is inside your TestRedux, should be inside your index.js file as follows:
render(
<Provider store={Store}>
<App/>
</Provider>,
document.getElementById('root')
)
import of course your store. That is assuming you haven't made any other changes in your initial index.js file.
I am new to react-native and I am trying to implement a simple application using StackNavigation and react-redux with welcome and signup screens. I have configured both the screens using StackNavigation but for some reasons , only the SignUp screen pops up when the app starts. Below are my files :
Index.js
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('MyApp', () => App);
App.js
import React, { Component } from 'react';
import { Provider, connect } from "react-redux";
import { addNavigationHelpers } from "react-navigation";
import StackNavConfig from "./js/config/routes";
import getStore from "./js/store";
const AppNavigator = StackNavConfig;
const initialState = AppNavigator.router.getActionForPathAndParams('Welcome');
const navReducer = (state = initialState, action) => {
const newState = AppNavigator.router.getStateForAction(action, state);
return newState || state;
};
const AppWithNavigationState = connect(state => ({
nav: state.nav,
}))(({ dispatch, nav }) => (
<AppNavigator navigation={addNavigationHelpers({ dispatch, state: nav })} />
));
const store = getStore(navReducer);
class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
export default App;
js/config/routes.js
import Welcome from "../components/Welcome/view/Welcome";
import SignUp from "../components/SignUp/view/SignUp";
import { StackNavigator } from "react-navigation";
const Routes = {
Welcome: { screen: Welcome , path: ''},
SignUp: { screen: SignUp , path : '/signup'},
};
const RoutesConfig = {
initialRouteName: 'Welcome',
headerMode: 'none',
};
export default StackNavConfig = StackNavigator(Routes, RoutesConfig);
store.js
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import getRootReducer from "./reducers/index";
export default function getStore(navReducer) {
const store = createStore(
getRootReducer(navReducer),
undefined,
applyMiddleware(thunk)
);
return store;
}
Below are my components
Welcome.js
import React from 'react';
import {
View,
Image} from 'react-native';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as welcomeActions from "../actions/WelcomeActions";
import { welcomeStyles } from '../styles/WelcomeStyles';
class Welcome extends React.Component {
constructor(){
super();
this.state = { };
}
render(){
return (
<View style = {welcomeStyles.mainContainer}>
<Text>Welcome</Text>
</View>
);
}
}
export default connect(
state => ({
}),
dispatch => bindActionCreators(welcomeActions, dispatch)
)(Welcome);
SignUp.js
import React from 'react';
import {
View,
Image} from 'react-native';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as welcomeActions from "../actions/SignUpActions";
import { signUpStyles } from '../styles/SignUpStyles';
class Welcome extends React.Component {
constructor(){
super();
this.state = { };
}
render(){
return (
<View style = {signUpStyles.mainContainer}>
<Text>SignUp</Text>
</View>
);
}
}
export default connect(
state => ({
}),
dispatch => bindActionCreators(signUpActions, dispatch)
)(SignUp);
I also have action and reducer files for each of my component.But they are blank as of now , since I haven't yet implemented the redux part.I am combining the reducers as below.
import { combineReducers } from "redux";
import welcomeReducer from "../components/Welcome/reducers/WelcomeReducer";
import signUpReducer from "../components/SignUp/reducers/SignUpReducer";
export default function getRootReducer(navReducer) {
return combineReducers({
nav: navReducer,
welcomeReducer : welcomeReducer,
signUpReducer : signUpReducer,
});
}
As mentioned before , even after setting the initialRouteName to Welcome in my routes.js , the SignUp screen appears first everytime I launch the app. Please help
I found out what was the issue. I was calling this.props.navigate inside the render function by mistake which was causing the navigation to different screen.
I am using Redux with a React Native app, and am getting a red box error when trying to integrate Redux-Persist. As soon as I navigate to the initial screen which has a ProfileForm and has the this.props.age piece of state, I see this:
TypeError: Cannot read property "age" of undefined
I am not quite sure where I am going wrong. I have set initial value of age = 0 in the reducer. So how is it undefined? Here is code that would be relevant:
reducers/UserReducer.js
import { CALCULATE_BMI, CALCULATE_AGE } from '../actions/types';
const INITIAL_STATE = { bmi: 0, age: 0 };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case CALCULATE_BMI:
return { ...state, bmi: action.bmi };
case CALCULATE_AGE:
return { ...state, age: action.age };
default:
return state;
}
};
reducers/index.js
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import userReducer from './UserReducer';
export default combineReducers({
user: userReducer,
form: formReducer,
});
store/index.js
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, persistCombineReducers } from 'redux-persist';
import storage from 'redux-persist/es/storage'; // default: localStorage if web, AsyncStorage if react-native
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import reducers from '../reducers';
const config = {
key: 'root',
storage,
};
const reducer = persistCombineReducers(config, { reducers });
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default () => {
const store = createStore(reducer, {}, composeEnhancers(applyMiddleware(thunk, logger)));
const persistor = persistStore(store);
return { persistor, store };
};
ProfileForm.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, Text, View, TouchableOpacity, Alert } from 'react-
native';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { reduxForm, Field } from 'redux-form';
import * as actions from '../actions';
import DatePickerModal from '../components/DatePickerModal';
class ProfileForm extends Component {
// other code here
<Field name="birthdate" component={DatePickerModal} />
{this.props.age === 0 ? null : (
<Text style={styles.labelStyle}>{`Age: ${this.props.age}`}</Text>
)}
//other code here
}
const mapStateToProps = state => ({
age: state.user.age,
});
export default compose(connect(mapStateToProps, actions), reduxForm({ form: 'Profile', validate }))(
ProfileForm,
);
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/es/integration/react';
import MainNavigator from './routes';
import configureStore from './store';
const { persistor, store } = configureStore();
export default class App extends Component {
// other code here
render() {
return (
<Provider store={store}>
<PersistGate persistor={persistor}>
<MainNavigator />
</PersistGate>
</Provider>
);
}
}
I have tried removing the empty object {} passed to createStore, setting it as undefined, and setting the initial values here instead, but nothing seems to work. Any guidance appreciated.