ExNavigation throws an error saying initialRoute is not defined - javascript

Hi I'm new to Expo but I've been having a hard time trying to run my code. I'm stuck at having the error: You must specify initialRoute or initialStack to initialize this StackNavigation even though I already set it up.
Here's my main.js
import Expo from 'expo'
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import {
NavigationProvider,
StackNavigation,
} from '#expo/ex-navigation'
import RootReducer from './src/reducers'
import Router from './src/navigation/Router'
const store = createStore(RootReducer)
const App = () => (
<Provider store={store}>
<NavigationProvider router={Router}>
<StackNavigation intitialRoute={Router.getRoute('splash')} />
</NavigationProvider>
</Provider>
)
Expo.registerRootComponent(App)
Here's my Router.js
import { createRouter } from '#expo/ex-navigation'
// Screens
import SplashScreen from '../screens/SplashScreen'
import LoginScreen from '../screens/LoginScreen'
const Router = createRouter(() => ({
splash: () => SplashScreen,
login: () => LoginScreen,
}))
export default Router
What seems to be the problem at my setup? I just followed the example on ExNavigation.
Here's my example on Sketch but can't make it run but will leave the link for the full code.

You have a typo in the prop's name in this part of the code
<StackNavigation intitialRoute={Router.getRoute('splash')} />
It is initialRoute instead of intitialRoute.

Related

RTL "Received value must be an HTMLElement or an SVGElement. Received has value: null" due to having to use ReactDOM.render() in test

I'm pretty confident this is due to the RTL render not being used, but I'm not sure where the render should go given I apparently have to use ReactDOM.react. At least it was needed to resolve one 4-5 errors I got along the way.
App and test code...
// App.jsx
import React from 'react';
import { Provider } from 'react-redux';
import { compose } from 'redux';
import { Switch, Route } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router';
import Authentication from './Authentication';
import configureStore, { history } from '../services/history';
const App = () => {
const protectedRoute = compose(Timers, RequireAuth);
const store = configureStore();
return (
<div data-testid='App'>
<Provider store={store}>
<ConnectedRouter history={history}>
<Switch>
<Route exact path='/' component={Authentication} />
</Switch>
</div>
</ConnectedRouter>
</Provider>
</div>
);
};
export default App;
// Authentication.jsx
import React, { Component } from 'react';
export default class Authentication extends Component {
render() {
return (
<div data-testid='Authentication' id='auth'>
...
</div>
);
}
}
Started out with this test:
// Authentication.test.jsx
import React from 'react';
import { render, screen } from '#testing-library/react';
import Authentication from './Authentication';
test('authentication page renders', () => {
render(<Authentication />);
const auth = screen.getByTestId('Authentication');
expect(auth).toBeInTheDocument();
});
Which resulted in:
Error: Uncaught [Error: Could not find "store" in the context of "Connect(Form(Connect(Signin)))". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(Form(Connect(Signin))) in connect options.]
Addressing this issue, and 4-5 other subsequent errors, has resulted in the following:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { render, screen } from '#testing-library/react';
import '#testing-library/jest-dom';
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';
import Authentication from './Authentication';
import { MemoryRouter } from 'react-router-dom';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
const store = mockStore({
auth: {
authenticated: true,
},
});
test('authentication page renders', () => {
const div = document.createElement('div');
ReactDOM.render(
<Provider store={store}>
<MemoryRouter>
<Authentication />
</MemoryRouter>
</Provider>,
div
);
const authentication = screen.queryByTestId('Authentication');
expect(authentication).toBeInTheDocument();
});
Which results in:
received value must be an HTMLElement or an SVGElement.
Received has value: null
28 | );
29 | const authentication = screen.queryByTestId('Authentication');
> 30 | expect(authentication).toBeInTheDocument();
| ^
31 | });
32 |
Again, pretty sure this is from not using RTLs render. Not sure where it should go and adding it creates the first error I had so I'm going in circles.
Any suggestions?
If it is helpful I could retrace all my previous steps and post the various error messages which led me to this point.
Well, somewhere along the line of addressing the various error messages that came up, one fix was adding ReactDOM.render()... thought it was necessary, turns out it was not.
This is sufficient and works:
import React from 'react';
import { Provider } from 'react-redux';
import { render, screen } from '#testing-library/react';
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';
import { MemoryRouter } from 'react-router-dom';
import '#testing-library/jest-dom';
import Authentication from './Authentication';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
const store = mockStore({
auth: {
authenticated: true,
},
});
test('authentication page renders', () => {
render(
<Provider store={store}>
<MemoryRouter>
<Authentication />
</MemoryRouter>
</Provider>
);
const authentication = screen.getByTestId('Authentication');
expect(authentication).toBeInTheDocument();
});

React-testing-library: Could not find "store" in the context of component

I'm quite new to testing so try to be gentle! I am trying to set up react-testing-library and I'm stuck with a confusing error message:
I defined a custom renderer that contains all my providers incl. redux Provider:
import React from 'react';
import { render } from '#testing-library/react'
import { ThemeProvider } from 'styled-components';
import { defaultTheme } from 'shared/theme';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from 'reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));
const AllTheProviders = ({ children }) => {
return (
<Provider store={store}>
<ThemeProvider theme={defaultTheme}>
{children}
</ThemeProvider>
</Provider>
)
}
const customRender = (ui, options?) =>
render(ui, { wrapper: AllTheProviders, ...options })
// re-export everything
export * from '#testing-library/react'
// override render method
export { customRender as render }
But when trying to execute the test I am receiving the error Message:
Error: Uncaught [Invariant Violation: Could not find "store" in the
context of "Connect(withRouter(Header))". Either wrap the root
component in a , or pass a custom React context provider to
and the corresponding React context consumer to
Connect(withRouter(Header)) in connect options.]
As far as I can see, I included the store. Is there a way around this?
This question is not a duplicate of: Invariant Violation: Could not find "store" in either the context or props of "Connect(SportsDatabase)"
Since it involves a global renderer.
The store needs to be mocked in order to test properly. I suggest to use redux-mock-store library to achieve that but it's up to your preference.
What I would try in your case is the following in the test file:
import configureMockStore from 'redux-mock-store';
const mockStore = configureMockStore();
const store = mockStore({ /* here you can create a mock object for the reducer */ });
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Provider store={store}>
{ /* your components */ }
</Provider>, div);
ReactDOM.unmountComponentAtNode(div);
});
I hope this gives you the idea and helps!

TypeError: undefined is not an object (evaluating 'store.getState')

I'm following the Let’s Build: Cryptocurrency Native Mobile App With React Native + Redux tutorial.
When I create my store in App.js, the app works fine
import { createStore, applyMiddleware, compose } from 'redux';
import devTools from 'remote-redux-devtools';
import React, { Component } from 'react';
import { Platform, View } from 'react-native';
import { Provider } from 'react-redux';
import promise from 'redux-promise';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import { Header, CryptoContainer } from './src/components';
import rootReducer from './src/reducers';
const middleware = applyMiddleware(thunk, promise, logger);
const Store = createStore(rootReducer, compose(middleware, devTools({
name: Platform.OS,
hostname: 'localhost',
port: 5678
}), ));
export default class App extends Component {
render() {
return (
<Provider store={Store}>
<View>
<Header />
<CryptoContainer />
</View>
</Provider>
);
}
}
but when I move the store logic to a new file ./src/Store.js,
import { Platform } from 'react-native';
import { createStore, applyMiddleware, compose } from 'redux';
import devTools from 'remote-redux-devtools';
import promise from 'redux-promise';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import rootReducer from './reducers';
const middleware = applyMiddleware(thunk, promise, logger);
const Store = createStore(rootReducer,compose(middleware,devTools({
name: Platform.OS,
hostname: 'localhost',
port: 5678
}),
)
);
export default Store;
and use it in App.js like
import React, { Component } from 'react';
import { View } from 'react-native';
import { Provider } from 'react-redux';
import { Header, CryptoContainer } from './src/components';
import { Store } from './src/Store';
export default class App extends Component {
render() {
return (
<Provider store={Store}>
<View>
<Header />
<CryptoContainer />
</View>
</Provider>
);
}
}
I get
TypeError: undefined is not an object (evaluating 'store.getState')
What's causing my build (expo start) to fail when I import Store.js?
It seems the import statement is not right. It should be:
import Store from './src/Store';
if you're importing a single named export
e.g where you've done export const MyComponent = () => {} you'd import it like import { MyComponent } from "./MyComponent"
if you're importing a default export e.g where you've done const MyComponent = () => {} export default MyComponent you'd import it like import MyDefaultComponent from "./MyDefaultExport"
I got this error because I was exporting the wrong component from my main App file.
I was exporting this:
import React from 'react'
import { Provider } from 'react-redux'
import { createAppContainer } from 'react-navigation'
import Navigator from './src/components/Navigator'
import { store } from './src/store'
const App = createAppContainer(Navigator);
const Wrapped = props => (
<Provider store={store}>
<App />
</Provider>
)
export default Provider; // wrong!
That last line should be:
export default Wrapped; // right!
The answer from Itunu Adekoya shows that you can decide how you want to export / import, and in this case about personal preference, as there isn't a perf difference.
In the case where you have a lot of exports from a file, and perhaps some are unrelated or won't all be used together, it is better to export them individual as consts and then in other file only import what you need via import { } format, this will be sure to only include relevant imprts
in my case its casing & named import issue. imported as
import store from './Redux/Store'
it should be
import {Store} from './Redux/Store'

Warning: Did not expect server HTML to contain a <li> in <ul>. in React/Redux Server side Rendering

I am doing Server Side Rendering for the first time with React and Redux and seeming to be having a little difficulty. I am getting the warning:
Warning: Did not expect server HTML to contain a <li> in <ul>.
I have looked this up and it means that there is a html tree mismatch. I am not sure how that is. Is there an obvious way to fix it? Here is the code I have that is throwing the warning.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import actions from '../actions';
class UsersList extends Component {
componentDidMount() {
if (this.props.users.length > 0) {
return;
}
this.props.fetchUsers();
}
render() {
const { users } = this.props;
return (
<div>
<ul>
{users.map(user => {
return <li key={user.id}>{user.name}</li>;
})}
</ul>
</div>
);
}
}
const stateToProps = state => {
return {
users: state.users
};
};
const dispatchToProps = dispatch => {
return {
fetchUsers: () => dispatch(actions.fetchUsers())
};
};
const loadData = store => {
return store.dispatch(actions.fetchUsers());
};
export { loadData };
export default connect(stateToProps, dispatchToProps)(UsersList);
Here is the client.js:
// Startup point for the client side application
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import Routes from './Routes';
import reducers from './reducers';
const store = createStore(reducers, {}, applyMiddleware(thunk));
ReactDOM.hydrate(
<Provider store={store}>
<BrowserRouter>
<div>{renderRoutes(Routes)}</div>
</BrowserRouter>
</Provider>,
document.querySelector('#root')
);
The problem was that since the server had rendered the list of users already, it had a ul with lis. But when the client loaded there was no initial data so there was only an ul and no lis to accompany it.
To fix this problem, which I think not many will have because you need to do this anyway in server side rendering is to pass some initial state into the createStore redux function:
You will need to do this in two places. In the html on your server side and in your entry point on the client side.
Short example could be:
<html>
<head></head>
<body>
<div id="root">${content}</div>
<script>
window.INITIAL_STATE = ${serialize(store.getState())}
</script>
<script src="bundle.js"></script>
</body>
</html>
As you can see we have to set the initial state to the store that you created on your server side.
On your client side:
// Startup point for the client side application
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import Routes from './Routes';
import reducers from './reducers';
const store = createStore(reducers, window.INITIAL_STATE, applyMiddleware(thunk));
ReactDOM.hydrate(
<Provider store={store}>
<BrowserRouter>
<div>{renderRoutes(Routes)}</div>
</BrowserRouter>
</Provider>,
document.querySelector('#root')
);
Now you have access to this global variable window.INITIAL_STATE and you just pass that through into the second argument of createStore which is the initial state.
I'm posting here now because I was searching this exact issue with nextJS SSG. Just like Dave Newton mentioned, in the jsx return I would simply add a check and not render the <ul> if it is empty due to a conditional check on the <li>'s. Something like this:
{Object.keys(el[i]).length > 0 ?
<ul>
{getKeys(docs, item, el).map(
([key, value], i) => {
const name = `${docs[item][el][key].name}`
const path = `${docs[item][el][key].path}`
return (name !== "undefined") && (
<li key={i}><a href={path}>{name}</a></li>
)}
)}
</ul>
: ''
}

webpack 2 hot reload not rerender

I'm working on a Universal React project, my client entry point is:
import React from 'react'
import {render} from 'react-dom'
import {Provider} from 'react-redux'
import {AppContainer} from 'react-hot-loader'
import {Router, browserHistory} from 'react-router'
import {syncHistoryWithStore} from 'react-router-redux'
import {addLocaleData} from 'react-intl'
import it from 'react-intl/locale-data/it'
import en from 'react-intl/locale-data/en'
import IntlProvider from 'shared/containers/IntlProvider'
import configureStore from 'shared/configureStore'
import routes from 'shared/routes'
import {isDev, isLive} from 'shared/config'
[en, it].forEach(addLocaleData)
const hook = document.getElementById('app')
const initialState = JSON.parse(hook.getAttribute('data-initial-state'))
const store = configureStore(initialState)
const history = syncHistoryWithStore(browserHistory, store)
let content = (
<Provider store={store}>
<IntlProvider key="intl">
<Router history={history}>
{routes}
</Router>
</IntlProvider>
</Provider>
)
if (isLive) {
content = <AppContainer>{content}</AppContainer>
}
function renderApp() {
render(content, hook)
}
if (isLive) {
module.hot.accept('./index.js')
module.hot.accept('../shared/routes', renderApp)
}
renderApp()
On component changes, the reload seems to work, but no render is applied..
maybe it happens before the hot reload trick happens?
NOTE my routes configuration is classic non dymanic routes for now.
I had the same problem because I just forgot to add code for modules replacing
if (module.hot) {
module.hot.accept(
"./App",
() => {
const NextApp = require("./App").App; // THIS LINE
render(NextApp);
},
);
}

Categories