I have a react native app, this error start to show up after I detached from expo to pure react native, I am a beginner I don't have much experience with react-native.
I tried removing node_modules and installing the dependencies with npm install.
I have included package.json and App.js
App screenshot
package.json
{
"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"test": "node ./node_modules/jest/bin/jest.js --watchAll"
},
"jest": {
"preset": "react-native"
},
"dependencies": {
"#babel/runtime": "^7.4.3",
"#expo/samples": "2.1.1",
"date-and-time": "^0.6.3",
"expo-core": "^3.0.1",
"expo-file-system": "^4.0.0",
"expo-font-interface": "^3.0.0",
"expo-image-loader-interface": "^3.0.0",
"expo-permissions-interface": "^3.0.0",
"expo-react-native-adapter": "^3.0.1",
"firebase": "^5.7.2",
"native-base": "^2.10.0",
"react": "16.5.0",
"react-native": "0.55.4",
"react-native-animatable": "^1.3.1",
"react-native-button": "^2.3.0",
"react-native-datepicker": "^1.7.2",
"react-native-dropdownalert": "^3.10.0",
"react-native-elements": "^0.19.1",
"react-native-firebase": "^5.2.3",
"react-native-parallax-scroll-view": "^0.21.3",
"react-native-ratings": "^6.3.0",
"react-native-splash-screen": "^3.2.0",
"react-native-status-bar-height": "^2.2.0",
"react-native-unimodules": "^0.2.0",
"react-native-vector-icons": "^6.4.2",
"react-navigation": "^2.18.2",
"scheduler": "^0.13.6"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0",
"jest": "^24.7.1"
},
"private": true
}
App.js
import React from "react";
import { Platform, StatusBar, StyleSheet, View, Text } from "react-native";
import { Icon } from "react-native-elements";
import AppNavigator from "./navigation/AppNavigator";
import MainTabNavigator from "./navigation/MainTabNavigator";
import Firebase from "./Firebase";
import SplashScreen from 'react-native-splash-screen'
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoadingComplete: false,
isUserLogged: false,
isAuthenticationReady: false
};
Firebase.auth().onAuthStateChanged(this.onAuthStateChanged);
}
componentDidMount() {
SplashScreen.hide();
}
componentWillUnmount() {
this.onTokenRefreshListener();
this.notificationDisplayedListener();
this.notificationListener();
}
onAuthStateChanged = user => {
this.setState({ isAuthenticationReady: true });
this.setState({ isUserLogged: !!user });
};
render() {
if (
!this.state.isLoadingComplete &&
!this.props.skipLoadingScreen &&
!this.state.isAuthenticationReady
) { return <Text />
/*return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
autoHideSplash={true}
/>
);*/
} else {
// As soon as app finishs loading and splash screen hides
// Check if user loggedIn
// Firebase.auth().onAuthStateChanged(user => {
// if (user) {
// this.setState({ isUserLogged: true });
// console.log(user.providerData[0].phoneNumber);
// } else {
// console.log("No user logged in yet!");
// }
// });
return (
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
{this.state.isUserLogged ? <MainTabNavigator /> : <AppNavigator />}
</View>
);
}
}
_loadResourcesAsync = async () => {
return Promise.all([
Asset.loadAsync([
require("./assets/images/algeria_flag.png"),
require("./assets/images/login_bg.jpg"),
require("./assets/images/road.jpg")
]),
Font.loadAsync({
// This is the font that we are using for our tab bar
...Icon.Ionicons.font,
...Icon.EvilIcons.font,
// We include SpaceMono because we use it in HomeScreen.js. Feel free
// to remove this if you are not using it in your app
"space-mono": require("./assets/fonts/SpaceMono-Regular.ttf"),
questrial: require("./assets/fonts/Questrial-Regular.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
PatuaOne: require("./assets/fonts/PatuaOne-Regular.ttf")
})
]);
};
_handleLoadingError = error => {
// In this case, you might want to report the error to your error
// reporting service, for example Sentry
console.warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff"
}
});
You can't do this in render() method:
// As soon as app finishs loading and splash screen hides
// Check if user loggedIn
// Firebase.auth().onAuthStateChanged(user => {
// if (user) {
// this.setState({ isUserLogged: true });
// console.log(user.providerData[0].phoneNumber);
// } else {
// console.log("No user logged in yet!");
// }
// });
You add that in componentWillMount usually. As the error indicates, you are calling setState inside render which causes infinite loop.
EDIT:
Also you should unsubscribe from firebase on unmounting. That means you should do something like this this.firebaseUnsubscriber = Firebase.auth().onAuthStateChanged(user => {...}). In componentWillUnmount add if(this.firebaseUnsubscriber) this.firebaseUnsubscriber()
Related
I am using octa-react library for authentication here. I have also given the dependencies below. I'm trying to pass my config data to octa login page if its authenticated then redirect to admin page in the project. In terminal its not showing any error but when I run this code its showing me this error. I'm stuck with this from last three days.
No routes matched location "/"
App.js
import React,{ PureComponent } from "react";
import axios from "axios";
import { BrowserRouter as Router, Route, Routes, useNavigate } from "react-router-dom";
import { OktaAuth, toRelativeUrl } from '#okta/okta-auth-js';
import { Security, LoginCallback, SecureRoute } from "#okta/okta-react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { createBrowserHistory } from "history";
import Home from "./Home";
import { allReducers } from "./redux/reducers";
import Loader from "./views/Common/Loader";
const browserHistory = createBrowserHistory();
const oktaauth = new OktaAuth(config.oidc);
const store = createStore(
allReducers,
{},
window.devToolsExtension && window.devToolsExtension()
);
const HasAccessToRouter = ({ data }) => {
const history = useNavigate();
const restoreoriginalUri = async (_oktaAuth, originalUri) => {
history.replace(toRelativeUrl(originalUri || '/', window.location.origin));
};
return (
<Security {...data.oidc} oktaAuth={oktaauth} restoreOriginalUri={restoreoriginalUri} >
<SecureRoute path="/" exact element={ <Home data={data} />}/>
<Routes>
<Route exact path="/implicit/callback" element={LoginCallback} />
</Routes>
</Security>
);
};
class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
isLoading: true,
response: {},
};
}
componentDidMount() {
this.getSettingsFromFile();
}
getSettingsFromFile = async () => {
try {
const response = await axios.get(
`${
process.env.PUBLIC_URL
? process.env.PUBLIC_URL
: `${window.location.origin}`
}/settings.json`
);
localStorage.setItem("apiUrl", response.data.API_URL || "");
this.setState({
isLoading: false,
response: response.data,
//dashboardtype:""
});
} catch (error) {
this.setState({
isLoading: false,
response: {},
});
}
};
render() {
const { response, isLoading } = this.state;
if (isLoading) {
return <Loader />;
}
return (
<div>
<Provider store={store}>
<Router
history={browserHistory}
basename={process.env.PUBLIC_URL || "/admini"}>
<Routes>
<Route element={ <HasAccessToRouter data={response} /> } />
</Routes>
</Router>
</Provider>
</div>
);
}
}
export default App;
Home.js
import { useOktaAuth } from "#okta/okta-react";
import React, { useEffect, useState } from "react";
import DefaultLayout from "./containers/DefaultLayout/DefaultLayout";
// import Login from "./Login";
import { Spin, Button } from "antd";
import { isEmpty } from "lodash";
const Home = (props) => {
const { authState, oktaAuth } = useOktaAuth();
const [userInfo, setUserInfo] = useState(null);
useEffect(() => {
if (!authState.isAuthenticated) {
// When user isn't authenticated, forget any user info
setUserInfo(null);
} else {
oktaAuth.getUser().then((info) => {
setUserInfo(info);
});
}
}, [authState, oktaAuth ]); // Update if authState changes
// redirect to okta login
const login = async () => {
oktaAuth.signInWithRedirect();
};
return (
<div>
{authState.isAuthenticated !== null && (
<div>
{authState.isAuthenticated && !isEmpty(userInfo) ? (
<div>
<DefaultLayout {...props} />
</div>
) : (
<div className="spinner">
<Spin tip="Loading..." />
</div>
)}
{!authState.isAuthenticated && (
<div>
<p>Please login to access the portal.</p>
<Button id="login-button" type={"primary"} onClick={login}>
Login
</Button>
</div>
)}
</div>
)}
</div>
);
};
export default Home;
package.json
"dependencies": {
"#ant-design/icons": "^4.7.0",
"#coreui/coreui": "^4.2.0",
"#coreui/coreui-plugin-chartjs-custom-tooltips": "^1.3.1",
"#coreui/icons": "2.1.0",
"#coreui/react": "^4.3.0",
"#okta/okta-auth-js": "^6.7.6",
"#okta/okta-react": "^6.5.0",
"#okta/okta-signin-widget": "^6.5.0",
"antd": "^4.21.7",
"antd-password-input-strength": "^2.0.1",
"axios": "^0.27.2",
"bootstrap": "^5.2.0",
"classnames": "^2.3.1",
"core-js": "^3.23.5",
"cross-env": "7.0.3",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"flag-icon-css": "^3.3.0",
"font-awesome": "^4.7.0",
"history": "^5.3.0",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"moment-timezone": "^0.5.34",
"node-sass": "^7.0.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-app-polyfill": "^3.0.0",
"react-chartjs-2": "^4.3.1",
"react-datalist": "^4.0.0",
"react-datalist-field": "^20.3.1",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-hot-loader": "^4.13.0",
"react-idle-timer": "^5.4.1",
"react-loadable": "^5.5.0",
"react-redux": "^8.0.2",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-spinners": "^0.13.3",
"react-test-renderer": "^18.2.0",
"reactstrap": "^9.1.2",
"redux": "^4.2.0",
"redux-thunk": "^2.4.1",
"simple-line-icons": "^2.5.5"
}
I'm creating a react native app that connects to firebase.
However, when I started my app in slow internet speeds, it took a while to load, and the code showed me that this was due to the wait for the authstate listener being slow on slow connections. On airplane mode, it works fine.
How can I make the app load faster, even with slow internet speeds?
import { getApps, initializeApp } from 'firebase/app';
// import 'firebase/compat/auth'
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "firebase/auth";
// import 'firebase//firestore'
import { getFirestore, collection, addDoc, query, where, getDocs, deleteDoc, doc, setDoc, serverTimestamp } from "firebase/firestore"
import AsyncStorage from '#react-native-async-storage/async-storage';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {*****
};
// Initialize Firebase
if (!getApps().length) {
console.log('initializing firebase');
const app = initializeApp(firebaseConfig);
}
Packages:
{
"name": "tut3",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"#gorhom/bottom-sheet": "^4",
"#react-native-async-storage/async-storage": "^1.17.2",
"#react-native-community/datetimepicker": "4.0.0",
"#react-native-community/google-signin": "^5.0.0",
"#react-native-firebase/app": "^14.7.0",
"#react-native-firebase/auth": "^14.7.0",
"#react-native-google-signin/google-signin": "^7.2.2",
"#react-navigation/bottom-tabs": "^6.2.0",
"#react-navigation/material-bottom-tabs": "^6.1.1",
"#react-navigation/native": "^6.0.8",
"#react-navigation/native-stack": "^6.5.2",
"#react-navigation/stack": "^6.1.1",
"expo": "~44.0.0",
"expo-camera": "^12.1.2",
"expo-fast-image": "^1.1.3",
"expo-file-system": "~13.1.4",
"expo-google-app-auth": "~8.3.0",
"expo-image-picker": "^12.0.2",
"expo-location": "~14.0.1",
"expo-status-bar": "^1.2.0",
"expo-updates": "~0.11.6",
"firebase": "^9.6.10",
"moment": "^2.29.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-action-button": "^2.8.5",
"react-native-dropdown-picker": "^5.3.0",
"react-native-gesture-handler": "~2.1.0",
"react-native-gifted-chat": "^0.16.3",
"react-native-image-crop-picker": "^0.37.3",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-maps": "0.29.4",
"react-native-onboarding-swiper": "^1.2.0",
"react-native-paper": "^4.12.0",
"react-native-reanimated": "~2.3.1",
"react-native-safe-area-context": "^4.2.4",
"react-native-screens": "^3.13.1",
"react-native-skeleton-placeholder": "^5.0.0",
"react-native-stars": "^1.2.2",
"react-native-vector-icons": "^9.1.0",
"react-native-web": "0.17.1",
"reanimated-bottom-sheet": "^1.0.0-alpha.22",
"shorthash": "^0.0.2",
"styled-components": "^5.3.5"
},
"devDependencies": {
"#babel/core": "^7.12.9"
},
"private": true
}
Here is my routes folder that determines what to show on the app until the app initialization is done:
import React, { useContext, useState, useEffect } from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { auth } from './AuthProvider';
// import 'firebase/compat/auth'
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "firebase/auth";
// import 'firebase//firestore'
import { getFirestore, collection, addDoc, query, where, getDocs, deleteDoc, doc, setDoc } from "firebase/firestore"
import { AuthContext } from './AuthProvider';
import AuthStack from './AuthStack';
import AppStack from './AppStack';
import AsyncStorage from '#react-native-async-storage/async-storage';
const Routes = () => {
const { user, setUser } = useContext(AuthContext);
const [initializing, setInitializing] = useState(true);
const onAuthStateChanges = (user) => {
setUser(user);
if (initializing) setInitializing(false);
console.log(user)
};
useEffect(() => {
const subscriber = onAuthStateChanged(auth, onAuthStateChanges);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing) return null;
return (
<NavigationContainer>
{user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
};
export default Routes;
Thanks!
EDIT:
After the suggested answer, this is what I've implemented that seems to be working for me. Idea is if the user was previously logged in and exited the app without logging out, then load the appstack.
const Routes = () => {
const { user, setUser } = useContext(AuthContext);
const [initializing, setInitializing] = useState(true);
const [previousUser, setPreviousUser] = useState(null);
const onAuthStateChanges = (user) => {
setUser(user);
AsyncStorage.setItem('user', JSON.stringify(user));
if (initializing) setInitializing(false);
console.log(user)
};
useEffect(() => {
AsyncStorage.getItem('user').then((value) => {
if (value) {
setPreviousUser(true)
setUser(JSON.parse(value))
}
else {
setPreviousUser(false)
}
})
const subscriber = onAuthStateChanged(auth, onAuthStateChanges);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing && user) return (
<NavigationContainer>
<AppStack />
</NavigationContainer>
)
if (initializing && !user) return (
<NavigationContainer>
<AuthStack />
</NavigationContainer>
)
return (
<NavigationContainer>
{!initializing && user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
};
The call to initializeApp is synchronous and doesn't need to call the server, so should run pretty quickly and at a speed unrelated to your internet connection.
But onAuthStateChanged waits for the auth state to be restored, which does require a call to the servers to check whether the user's credentials are still valid (for example, that their account wasn't disabled). On a slow internet connection this may take some time.
Since most of such calls will be successful, a common trick is to assume they will succeed and then course correct if it turns out that assumption was wrong. To implement this, you'll need to store a token value in local storage when the user has successfully signed in, and then use that value to determine your initial navigation instead of waiting for onAuthStateChanged.
Firebaser Michael Bleigh talked about this at Google I/O in this video on Architecting Mobile Web Apps.
I've used this test in the past with a React app without any issues:
import { render, fireEvent, screen, waitFor } from '#testing-library/react'
import { RelatedContent } from '../components/relatedcontent'
import { onValue } from '../components/firebase'
jest.mock('../components/firebase')
test('RelatedContent -> displays related content', async () => {
let fakeData = {
'flex-new-row': 20,
'chronlabs': 25
}
let snapshot = {val: () => fakeData}
onValue.mockImplementation((ref, callback) => {
callback(snapshot)
return jest.fn()
})
render(<RelatedContent numRelated = {5}/>)
await waitFor(() => expect(document.querySelector("a[href='/flex-new-row']")).toBeTruthy())
await waitFor(() => expect(document.querySelector("a[href='/chronlabs']")).toBeTruthy())
})
Now I'm using the same test on a Next.js app, and I'm getting the following error:
TypeError: _firebase.onValue.mockImplementation is not a function
Update
The RelatedContent component looks like:
import React, { useState, useEffect } from 'react'
import { db, onValue, ref } from './firebase'
const RelatedContent = ({ numRelated }) => {
const [related, setRelated] = useState([])
useEffect(() => {
let unsubscribe = onValue(ref(db, `posts/related`), snapshot => {
let _related = Object.keys(snapshot.val())
setRelated(_related)
})
return () => unsubscribe()
}, [])
return(
<div className = 'Related'>
{related.slice(0, numRelated).map((elem, i) =>
<Link href = {elem}>Whatever</Link>
)}
</div>
)
}
export default RelatedContent
And the Firebase component looks like:
import { initializeApp } from 'firebase/app'
import { getDatabase, goOnline, goOffline, limitToLast, onDisconnect, onValue, orderByValue, push, query, ref, remove, runTransaction, update } from 'firebase/database'
const config = { ... }
const app = initializeApp(config)
const db = getDatabase(app)
export { db, dbt, goOnline, goOffline, limitToLast, onDisconnect, onValue, orderByValue, push, query, ref, remove, runTransaction, update }
package.json looks like:
{
"name": "app-next",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest"
},
"dependencies": {
"#primer/octicons-react": "^16.3.0",
"chart.js": "^2.7.2",
"firebase": "^9.6.4",
"gfm": "0.0.1",
"moment": "^2.29.1",
"next": "12.0.8",
"prismjs": "^1.26.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-markdown": "^8.0.0",
"rehype-katex": "^6.0.2",
"rehype-raw": "^6.1.1",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1"
},
"devDependencies": {
"#testing-library/jest-dom": "^5.16.1",
"#testing-library/react": "^12.1.2",
"eslint": "8.7.0",
"eslint-config-next": "12.0.8",
"eslint-plugin-promise": "^6.0.0",
"jest": "^27.4.7"
}
}
If I place the fake data and the onValue.mockImplementation() function before the test declaration, the test passes correctly.
The problem is that I've several tests with multiple definitions of the fake data, and I need to declare the fake data within every test.
If I do so, I get the error.
Any ideas why I am getting the following this "dispatch is not a function" error in my listEventsActionCreator function when it calls "dispatch(listEventsRequestedAction())" ???
If I comment out the lines in this method after the dispatch it actually then works which is strange.
Using react-create-app, with redux, typescript, thunk.
ERROR:
TypeError: dispatch(...) is not a function
CODE:
export function listEventsRequestedAction() {
return {
type: PlannerEventTypes.LIST_EVENTS_REQUESTED
}
}
export const listEventsReceivedAction = (events:PlannerEvent[]) => {
return {
type: PlannerEventTypes.LIST_EVENTS_RECEIVED,
events
}
}
export const listEventsErrorAction = (err:any) => {
return {
type: PlannerEventTypes.LIST_EVENTS_ERROR,
error: err
}
}
export const listEventsActionCreator = () => {
return (dispatch: any) => {
dispatch(listEventsRequestedAction()) // <== ERROR: TypeError: dispatch(...) is not a function
(API.graphql(graphqlOperation(listEvents)) as Promise<any>).then((results:any) => {
const events = results.data.listEvents.items
dispatch(listEventsReceivedAction(events))
}).catch((err:any) => {
// console.log("ERROR")
dispatch(listEventsErrorAction(err))
})
}
}
package.json
{
"name": "planner",
"version": "0.1.0",
"private": true,
"dependencies": {
"#types/graphql": "^14.0.7",
"#types/react-redux": "^6.0.10",
"aws-amplify": "^1.1.19",
"aws-amplify-react": "^2.3.0",
"date-fns": "^1.30.1",
"eslint": "^5.9.0",
"konva": "^2.5.1",
"moment": "^2.22.2",
"moment-timezone": "^0.5.23",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-draggable": "^3.0.5",
"react-konva": "^16.6.31",
"react-moment": "^0.8.4",
"react-redux": "^5.1.1",
"react-scripts-ts": "3.1.0",
"redux": "^4.0.1",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject"
},
"devDependencies": {
"#types/jest": "^23.3.10",
"#types/node": "^10.12.10",
"#types/react": "^16.7.10",
"#types/react-dom": "^16.0.11",
"#types/redux-logger": "^3.0.7",
"typescript": "^3.2.1"
}
}
index.tsx
import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { applyMiddleware, createStore } from 'redux'
import App from './App'
import './index.css'
import rootReducer from './reducers/index'
import registerServiceWorker from './registerServiceWorker'
import { createLogger } from 'redux-logger'
import thunkMiddleware from 'redux-thunk'
const loggerMiddleware = createLogger()
const store = createStore (
rootReducer,
applyMiddleware(
thunkMiddleware, // lets us dispatch() functions
loggerMiddleware // neat middleware that logs actions
)
)
render(
<Provider store={store}>
<App testStr='test' />
</Provider>
,document.getElementById('root') as HTMLElement
);
registerServiceWorker();
The problem is because of the syntax that you followed. You don't have a semicolon after dispatch(listEventsRequestedAction()) and since you follow it up with (API.graphql(graphqlOperation(listEvents) as Promise<any>) while compiling it is evaluted as dispatch(listEventsRequestedAction())(API.graphql(graphqlOperation(listEvents) as Promise<any>) and hence it gives you the error.
Adding a semicolon after dispatch(listEventsRequestedAction()) would work
export const listEventsActionCreator = () => {
return (dispatch: any) => {
dispatch(listEventsRequestedAction());
(API.graphql(graphqlOperation(listEvents)) as Promise<any>).then((results:any) => {
const events = results.data.listEvents.items
dispatch(listEventsReceivedAction(events))
}).catch((err:any) => {
// console.log("ERROR")
dispatch(listEventsErrorAction(err))
})
}
}
P.S. The semicolon is not required in Javascript and would not cause a
js error on its own. It could however cause an error if concatenating
with other scripts.
I'm getting this error:
<Provider> does not support changing store on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions.
I have a component with this:
import React, { Component } from 'react';
import {
AppRegistry,
NativeAppEventEmitter
} from 'react-native';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducers from './src/reducers';
import Onboarding from "./src/onboarding/Onboarding";
import Home from "./src/home/Home";
import codePush from 'react-native-code-push';
class Edmund extends Component {
...
startScreen() {
if (this.state.screen === "HOME" ) {
return (<Home />);
}
return (
<Onboarding />
);
}
render() {
return (
<Provider store={ createStore(reducers) }>
{ this.startScreen() }
</Provider>
)
}
AppRegistry.registerComponent('Edmund', () => Edmund)
My src/reducers/index.js file:
import { combineReducers } from 'redux';
export default combineReducers({
libraries: () => []
});
My packages:
{
"name": "Indigo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"lodash": "^4.13.1",
"react": "^15.2.0",
"react-native": "^0.27.1",
"react-native-apple-pay": "0.0.0",
"react-native-code-push": "^1.11.0-beta",
"react-native-loading-spinner-overlay": "^0.3.0",
"react-native-navigation": "^1.0.2",
"react-native-paged-scroll-view": "^2.0.1",
"react-native-progress": "^3.0.1",
"react-redux": "latest",
"redux": "^3.0.0",
"underscore": "^1.8.3"
},
"devDependencies": {
"eslint": "latest",
"eslint-config-airbnb": "latest",
"eslint-plugin-import": "^1.16.0",
"eslint-plugin-jsx-a11y": "latest",
"eslint-plugin-react": "latest"
}
}
I'm not even doing anything fancy so I don't get why there's this error. Can anyone help?
If you dig into the react-redux code a bit you see this
if (store !== nextStore) {
warnAboutReceivingStore()
}
So it would seem all you would have to do is move the createStore call outside.
store = createStore(reducers)
class Edmund extends Component {
...
startScreen() {
if (this.state.screen === "HOME" ) {
return (<Home />);
}
return (
<Onboarding />
);
}
render() {
return (
<Provider store={ store }>
{ this.startScreen() }
</Provider>
)
}
Haven't tested it but should work.
I got the same error and the workaround is to remove the DevTools.
<Provider store={store} >
<App />
</Provider>
In the component App's render() method, there is a:
<DevTools />
After I removed the DevTools, the error disappeared.
This is not a good solution, just for your reference.