Way to use react-router and redux on react-native - reactjs

I'm started to use react-native (i'm from react-js), and i'm trying to implement my first little app with a router and redux as I do in web development with reactjs.
But i met a problem, and i can't to fix it.
so i'm on this way :
Index.ios.js
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
import { Provider } from 'react-redux'
import { NavBar, Route, Router, Schema, TabBar, TabRoute } from 'react-native-router-redux';
import configureStore from './src/store/configureStore'
const store = configureStore()
import Index from './src/components/index'
class ole extends Component {
render() {
return (
<Provider store={store}>
<Router initial="index">
<Route name="index" component={Index} />
</Router>
</Provider>
)
}
}
AppRegistry.registerComponent('ole', () => ole);
store/configureStore.js
import { createStore, applyMiddleware } from 'redux'
import promise from 'redux-promise'
import reducer from '../reducers'
export default function configureStore(initialState){
const store = createStore(
reducer,
applyMiddleware(promise)
)
return store
}
reducers/index.js
import { combineReducers } from 'redux'
const INITIAL_STATE = {
test: [],
errors: undefined
}
initTestReducer = (state = INITIAL_STATE, action) => {
return state
}
export default combineReducers({
test: initTestReducer
})
if do exactly like that i get this error in my simulator on iOS :
Super expression must either be null or a function, not undefined
but if my index.ios.js look like that, it works perfectly :
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
import { Provider } from 'react-redux'
import { NavBar, Route, Router, Schema, TabBar, TabRoute } from 'react-native-router-redux';
import configureStore from './src/store/configureStore'
const store = configureStore()
import Index from './src/components/index'
class ole extends Component {
render() {
return (
<Provider store={store}>
<Index />
</Provider>
)
}
}
AppRegistry.registerComponent('ole', () => ole);
So error come from Router
get u an idea ?
Thank's a lot :)

Related

How to fix "Could not find "store" in either the context or props of "Connect(Provider)" issue (ReactJs, Redux, SimpleWebRTC)?

I am trying to launch the SimpleWebRTC app from here: https://docs.simplewebrtc.com/#/?id=getting-started
App.js file:
import React from "react";
import { Provider } from "react-redux";
import ReduxToastr from "react-redux-toastr";
import store from "./redux/store/index";
import Routes from "./routes/Routes";
const App = () => (
<Provider store={store}>
<Routes />
<ReduxToastr
timeOut={5000}
newestOnTop={true}
position="top-right"
transitionIn="fadeIn"
transitionOut="fadeOut"
progressBar
closeOnToastrClick
/>
</Provider>
);
export default App;
./redux/store/index.js file:
import { combineReducers } from "redux";
import sidebar from "./sidebarReducers";
import layout from "./layoutReducer";
import theme from "./themeReducer";
import app from "./appReducer";
import auth from "./authReducer";
import { reducer as simplewebrtc } from '#andyet/simplewebrtc';
import { reducer as toastr } from "react-redux-toastr";
export default combineReducers({
sidebar,
layout,
theme,
toastr,
app,
auth,
simplewebrtc
});
./redux/store/index.js file:
import { createStore, applyMiddleware } from "redux";
import thunk from 'redux-thunk';
import rootReducer from "../reducers/index";
const persistedState = localStorage.getItem('reduxState') ? JSON.parse(localStorage.getItem('reduxState')) : {}
var store
if(persistedState.app){
store = createStore(rootReducer, persistedState, applyMiddleware(thunk));
}else{
store = createStore(rootReducer, applyMiddleware(thunk));
}
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
export default store;
Chat.js file:
const API_KEY = '';
const ROOM_PASSWORD = 'test';
const CONFIG_URL = `https://api.simplewebrtc.com/config/guest/${API_KEY}`
const ROOM_NAME = 'uniq-room-name'
class _SimpleWebRtc extends React.Component {
constructor(props) {
super(props);
}
render(){
return (
<SWRTC.Provider configUrl={CONFIG_URL}> {/* <------- problem here */}
{/* Render based on the connection state */}
<SWRTC.Connecting>
<h1>Connecting...</h1>
</SWRTC.Connecting>
<SWRTC.Connected>
<h1>Connected!</h1>
<SWRTC.RequestUserMedia audio auto />
<SWRTC.Room name={ROOM_NAME} password={ROOM_PASSWORD}>
<SWRTC.RemoteAudioPlayer />
</SWRTC.Room>
</SWRTC.Connected>
</SWRTC.Provider>
)
}
}
const SimpleWebRtc = connect(store => ({simplewebrtc: store.simplewebrtc})) (_SimpleWebRtc)
When I trying run this code it returns a folloowing error for me:
app.js:58464 Uncaught Invariant Violation: Could not find "store" in either the context or props of "Connect(Provider)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(Provider)".
Do you have any ideas about what is wrong with this code and how to solve this issue?
I also faced this problem and solved the issue by updating the packages.
You have to use
react#^16.8.4
react-dom#^16.8.4
react-redux#^7.0.0
redux#^4.0.0
redux-thunk#^2.3.0
Here are the requirements for simplewebRTC
https://docs.simplewebrtc.com/#/ReactVersions

react native app stay blank after implementing redux-persist?

Everyone
i am trying to persist my store using redux-persist but after implementing it to my app.js, i get white screen, i looked for this error, and the only thing i could find was to purge the persistor in componentDidMount() and even that didn't work for me:
App.js:
import React from 'react';
import { AppLoading, Asset, Font } from 'expo';
import { PersistGate } from 'redux-persist/integration/react';
import { Ionicons } from '#expo/vector-icons';
import { Provider } from 'react-redux';
import storeConfig from './config/store';
import RootNavigation from './navigation/RootNavigation';
import Splash from './screens/Splash'
const {persistor, store} = storeConfig();
// normal code
render() {
if (!this.state.isLoadingComplete ) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
} else {
return (
<Provider store={store}>
<PersistGate loading={<Splash /> } persistor={persistor}>
<RootNavigation />
</PersistGate>
</Provider>
);
}
}
store.js :
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import logger from 'redux-logger';
import reducers from '../reducers';
const persistConfig = {
key: 'root',
storage,
};
const pReducer = persistReducer(persistConfig, reducers);
export const store = createStore(pReducer);
export const persistor = persistStore(store);

Where to set the visibility of Network Indicator with Redux?

I have several actions in my application which fetches data from an API. I am setting a "loading"-attribute in my redux-store, if the action is fetching. Now I want to show a network indicator the app is fetching data.
I found a quick&dirty solution but I am sure, that this is not the way to do it:
import React, { Component } from 'react';
import { AppRegistry, StatusBar } from 'react-native';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './app/reducers';
import App from './app/providers/App';
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(reducer);
class AppName extends Component {
render() {
store.subscribe(() => {
if(
store.getState().dishes.loading
|| store.getState().deals.loading
) StatusBar.setNetworkActivityIndicatorVisible(true);
else StatusBar.setNetworkActivityIndicatorVisible(false);
});
return (
<Provider store={store}>
<App />
</Provider>
);
}
}
AppRegistry.registerComponent('AppName', () => AppName);
What is the correct way to hook such a listener?
To avoid calling StatusBar.setNetworkActivityIndicatorVisible too many times, you can watch the changes in your state using componentWillReceiveProps in your connected component.
import AppContainer from './containers/AppContainer';
class AppName extends Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>
);
}
}
containers/AppContainer.js
import App from '../components/App.js';
const mapStateToProps = state => ({
loading: state.dishes.loading || state.deals.loading
});
export default connect(mapStateToProps)(App);
components/App.js
class App extends Component {
componentWillReceiveProps(nextProps) {
if (!this.props.loading && nextProps.loading) {
// Changing from `not loading` to `loading`
StatusBar.setNetworkActivityIndicatorVisible(true);
} else if (this.props.loading && !nextProps.loading) {
// Changing from `loading` to `not loading`
StatusBar.setNetworkActivityIndicatorVisible(false);
}
}
// ...
}

GraphQL query to pass mapQueriesToProps via connect() not firing

So, I'm attempting to set the results of a graphQL query to mapQueriesToProps, and then pass the result onto the main interface/view of my app via connect(), but the query is not firing (as confirmed by devTools):
My code is as follows:
App.js
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
// import { connect } from 'react-apollo';
import {
// gql,
graphql,
withApollo
} from 'react-apollo';
import gql from 'graphql-tag';
import * as actionCreators from '../actions/actionCreators';
// import client from '../apolloClient';
// import ApolloClient from 'apollo-client';
/*
Components
This is where the actual interface / view comes into play
Everything is in Main - so we import that one
*/
import Main from './Main';
const allPostsCommentsQuery = gql`
query allPostsCommentsQuery {
allPostses {
id
displaysrc
caption
likes
comments {
id
posts {
id
}
text
user
}
}
}
`;
const mapQueriesToProps = ({ ownProps, state }) => {
return {
posts: {
query: gql`
query allPostsCommentsQuery {
allPostses {
id
displaysrc
caption
likes
comments {
id
posts {
id
}
text
user
}
}
}
`,
// variables: {
// },
// forceFetch: false, // optional
// returnPartialData: false, // optional
},
};
};
export function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
}
var App = connect(
mapQueriesToProps,
mapDispatchToProps
)(Main);
export default App;
Main.js
import React from 'react';
import { Link } from 'react-router';
const Main = React.createClass({
render() {
return (
<div>
<h1>
<Link to="/">Flamingo City</Link>
</h1>
{/* We use cloneElement here so we can auto pass down props */}
{ React.cloneElement(this.props.children, this.props) }
</div>
);
}
});
export default Main;
My app.js into which App.js is imported into:
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute } from 'react-router'
import 'babel-polyfill';
import { ApolloProvider, graphql, gql } from 'react-apollo';
import client from './apolloClient';
/*
Import Components
*/
import App from './components/App';
import Single from './components/Single';
import PhotoGrid from './components/PhotoGrid';
/* Import CSS */
import css from './styles/style.styl';
/* Import our data store */
import store, { history } from './store';
/*
Error Logging
*/
import Raven from 'raven-js';
import { sentry_url } from './data/config';
if(window) {
Raven.config(sentry_url).install();
}
/*
Rendering
This is where we hook up the Store with our actual component and the router
*/
render(
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
</Route>
</Router>
</ApolloProvider>,
document.getElementById('root')
);
What am I overlooking?
I resolved the issue by doing the following:
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import {
gql,
graphql
} from 'react-apollo';
import * as actionCreators from '../actions/actionCreators';
/*
Components
This is where the actual interface / view comes into play
Everything is in Main - so we import that one
*/
import Main from './Main';
const allPostsCommentsQuery = graphql(gql`
query allPostsCommentsQuery {
allPostses {
id
displaysrc
caption
likes
comments {
id
posts {
id
}
text
user
}
}
}
`);
/*
This will bind our actions to dispatch (make the fire-able)
and make the actions available via props
*/
export function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
}
const App = connect(
mapDispatchToProps
);
export default App(allPostsCommentsQuery(Main));

Adding Routes to a React/Firebase app

Just starting to add React Routes to a React/firebase app. I had this code to read the data,
const fb = firebase
.initializeApp(config)
.database()
.ref();
fb.on('value', snapshot => {
const store = snapshot.val();
ReactDOM.render(
<App {...store} />
,
document.getElementById('root')
);
});
This worked correctly, with real time updates to the App.
I then started to play with Router,
ReactDOM.render(
<Router>
<Route path="/" component={App {...store}} />
</Router>
,
document.getElementById('root')
);
But the {...store} gives an error, unexpected token. Should I move the Firebase code lower down the tree into the App component or is there a different way?
uh the component=doesn't take that thing that you have there with ReactDOM.render()
As you have it right now: store will be undefined... so set:
let store = {} // at the top
Where is your actual component/class defined?
also you shouldn't creator render based on when Firebase shows up you should render first then when firebase shows up you can update the state.
So there is a lot that will need to be fixed here before this can work.
Here is my index.js:
also notice that store is the result of the configureStore (I'm assuming you want to use Redux as you have a store)...
import 'babel-polyfill'
import React from 'react'
import { render } from 'react-dom'
import Root from './root/containers/Root'
import './index.css'
import configureStore from './root/store'
import { syncHistoryWithStore } from 'react-router-redux'
import { browserHistory } from 'react-router'
const store = configureStore()
const history = syncHistoryWithStore(browserHistory, store)
render(
<Root store={store} history={history} />,
document.getElementById('root')
);
My store:
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import reducer from '../reducers'
import { database, initializeApp } from 'firebase'
import { firebaseConfig } from '../constants'
initializeApp(firebaseConfig)
export const rootRef = database().ref().child('/react')
export const dateRef = rootRef.child('/date')
export default function configureStore(preloadedState){
const store = createStore(
reducer,
preloadedState,
applyMiddleware(thunkMiddleware, createLogger())
)
return store
}
And my Root:
import React, { Component, PropTypes } from 'react'
import { Provider } from 'react-redux'
import routes from './routes'
import { Router, } from 'react-router'
class Root extends Component {
render() {
const { store, history } = this.props
return (
<Provider store={store}>
<Router history={history} routes={routes} />
</Provider>
)
}
}
Root.propTypes = {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}
Simplest Version to get started:
import React, { Component } from 'react'
import { firebaseConfig } from '../constants' //this is a must otherwise you have multiple versions of firebase running around...
initializeApp(firebaseConfig)
export const rootRef = database().ref().child('/root')
class App extends Component {
componentDidMount(){
initializeApp(firebaseConfig)
this.state = {store: {}}
rootRef.on('value', snapshot => {
this.setState({store: snapshot.val()});
}
}
render(){
let { store } = this.state
let childrenWithProps = React.Children
.map(this.props.children, function(child) {
return React.cloneElement(child, { store: store });
});
return <div>
{JSON.stringify(store)}
{childrenWithProps}
</div>
}
}
const Routes = (<Route component={App}><Route component={Comp1} path='/earg'/><Route component={Comp2} path='/earg'/></Route>)
render(Routes, document.getElementById('root'))
This is a lot of code and you'll need still more to get this going... I'd recommend a tutorial perhaps...
In the end, for a quick solution, I used an anonymous function to wrap the component,
<Route path="/" component={() => (<App {...store} />)} />

Resources