React-redux connect method unable to locate store in props - reactjs

I have a application structure that mostly mimics the redux real-world example but can't get past getting this error:
Uncaught Error: Invariant Violation: Could not find "store" in either the context or props of "Connect(Home)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Home)".
Here follows my application structure:
render
import { render, createFactory } from 'react'
import { Provider } from 'react-redux';
import router from './router/router'
import store from './flux/store'
window.onload = () => {
render(createFactory(Provider)({store: store},
() => router
), document.body)
};
Router
import { _ } from 'factories'
import { Router, IndexRoute, Route } from 'react-router'
import history from 'history/lib/createBrowserHistory'
import Home from '../components/home/home'
let route = _(Route),
index = _(IndexRoute);
let router = _(Router)({history: history()},
route({path: 'home', component: Home})
);
export default router;
Home Component
import React, { PropTypes } from 'react'
import { div } from 'factories'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux';
import * as users from '../../flux/actions/users'
class Home extends React.Component {
constructor() {
super();
this.state = {}
}
componentWillMount() {
console.log(this.props.users.user)
}
componentWillUnmount() {
}
render() {
return (
div({}, "Home")
)
}
}
export default connect(
state => {
return {
users: state.users
}
},
dispatch => bindActionCreators(users, dispatch)
)(Home)
This results in getting the above mentioned error. as you can see I am passing the store in the same manner as shown in the redux example.

The solution was found in redux troubleshooting docs. I needed to have my react-router return a function that created the actual router:
import { _ } from 'factories'
import { Router, IndexRoute, Route } from 'react-router'
import history from 'history/lib/createBrowserHistory'
import Home from '../components/home/home'
let route = _(Route),
index = _(IndexRoute);
const router = () =>
_(Router)({history: history()},
route({path: 'home', component: Home})
);
export default router;

Related

React With Redux Thunk and Apollo Graphql - How to access client.query?

This is my app.js
import React from 'react'
import { Provider } from 'react-redux'
import { View } from 'react-native'
import { createStore, applyMiddleware } from 'redux'
import ReduxThunk from 'redux-thunk'
import Reducers from './redux'
import Routes from './config/routes'
import { ApolloClient, HttpLink, InMemoryCache } from 'apollo-boost'
import { ApolloProvider } from 'react-apollo'
const cache = new InMemoryCache();
const client = new ApolloClient({
cache,
link: new HttpLink({
uri: '...',
}),
})
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
initialized: true
}
}
render() {
return (
<View style={{ flex: 1 }}>
<ApolloProvider client={client}>
<Provider store={store}>
<Routes />
</Provider>
</ApolloProvider>
</View>
)
}
}
const store = createStore(Reducers, {}, applyMiddleware(ReduxThunk))
export default App
Ok, so far...basic.
This will render the initial file of my route: welcome.js
import React from 'react'
import {...} from 'react-native'
import { Actions } from 'react-native-router-flux'
import style from './style'
import { connect } from "react-redux"
import gql from 'graphql-tag'
class Welcome extends React.Component {
constructor(props) {
const LOGIN_MUTATION = gql`
mutation {
login(
email:"test#test.com"
password:"1234"
) {token}
}
`
// Bellow will not work..I've no idea how to call the client that
// I set at <ApolloProvider client={client}>
client
.mutate({
mutation: LOGIN_MUTATION
})
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
const mapStateToProps = state => (
{
}
)
export default connect(mapStateToProps,
{
})(Welcome)
So, the client was defined on my app.js that's apply the provider and inject the routes.
I'd like to know how to be capable to execute the client defined at app,js into welcome.js
It's highly recommended that you switch for the new React Hooks version, using them, you can simply write const client = useApolloClient() to get access to your client instance:
import { useApolloClient } from '#apollo/react-hooks';
const Welcome = () => {
const client = useApolloClient();
return <h1>Welcome</h1>;
}
And regarding the ApolloProvider, it is configured in the same manner was you did, except that you can import it directly from the hooks package too, i.e import { ApolloProvider } from '#apollo/react-hooks -- and you can remove the react-apollo therefore.
See more details about hooks here: https://www.apollographql.com/docs/react/hooks-migration/.
But in case you really want to stay using class components, you can do:
import { getApolloContext } from 'react-apollo';
class Welcome extends React.Component {
...
}
Welcome.contextType = getApolloContext();
And then you'll be able to access the client using this.context.client inside your class:
class Welcome extends React.Component {
render() {
console.log('client', this.context.client);
return ...;
}
}
Welcome.contextType = getApolloContext();
You can use ApolloConsumer in your component to get access to the client:
To access the client directly, create an ApolloConsumer component and provide a render prop function as its child. The render prop function will be called with your ApolloClient instance as its only argument.
e.g.
import React from 'react';
import { ApolloConsumer } from "react-apollo";
const WithApolloClient = () => (
<ApolloConsumer>
{client => "We have access to the client!" /* do stuff here */}
</ApolloConsumer>
);

react-redux - Invariant Violation: Could not find "store" in either the context or props

I am trying to use redux persist and react-redux in my app.js file, but I am getting the following error:
Invariant Violation: Could not find "store" in either the context or props of "Connect(App)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(App)"
Here is the code for my app.js file, where the error is occurring.
import React from 'react';
import { Provider } from 'react-redux';
import StoreDetailsScreen from './screens/storeDetailsScreen';
import CustomerListScreen from './screens/customerListScreen';
import AddCustomerScreen from './screens/addCustomerScreen'
import AddTransactionsScreen from './screens/addTransactionScreen'
import TransactionListScreen from './screens/transactionListScreen'
import CustomerInfoScreen from './screens/CustomerInfoScreen'
import {connect} from 'react-redux'
import {daysFromTransaction} from './redux/reducer'
import {updateFrequency} from './redux/actions'
import {store, persistor} from './redux/store';
import { createSwitchNavigator, createStackNavigator, createMaterialTopTabNavigator } from 'react-navigation';
import {PersistGate} from 'redux-persist/integration/react'
const TransactionsNavigator = createMaterialTopTabNavigator({
AddTransactions: AddTransactionsScreen,
CustomerInfo: CustomerInfoScreen,
TransactionList: TransactionListScreen,
})
const CustomerNavigator = createStackNavigator({
CustomerList: CustomerListScreen,
AddCustomerForm: AddCustomerScreen,
Transactions: TransactionsNavigator,
});
const MainNavigator = createSwitchNavigator({
StoreDetailsForm: StoreDetailsScreen,
Customers: CustomerNavigator,
});
class App extends React.Component {
state = {
customers: this.props.customers,
isReady: false,
}
async componentWillMount() {
await Expo.Font.loadAsync({
'MaterialIcons': require('#expo/vector-icons/fonts/MaterialIcons.ttf')
});
updatedCustomers = this.state.customers.map(customer => {
let frequency = 0
currentDate = new Date()
customer.transactions.forEach(transaction => {
if (daysFromTransaction(transactionDate, currentDate) < 30)
frequency++;
})
return {
...customer,
frequency: frequency
}
})
this.props.updateFrequency([...updatedCustomers])
this.setState({isReady: true})
}
render() {
if (!this.state.isReady)
return <Expo.AppLoading/>
return (
<Provider store={store}>
<PersistGate persistor={persistor}>
<MainNavigator />
</PersistGate>
</Provider>
);
}
}
const mapStateToProps = state => {
customers: state.customers
}
export default connect(mapStateToProps,{updateFrequency: updateFrequency})(App)

React + Redux - Call a method of a component wrapped for the Redux Provider

Whats'up,
I am trying to test some react components that uses redux.
The default behavior should load by a rest call a list of options in a select input. This call is on the method componentDidMount() in my component.
The component works fine, but I cannot simulate the same behavior in my tests.
I cannot call the method componentDidMount() from my instance wrapped by Provider.
Can anyone help me with this
import React from 'react'
import {expect} from 'chai'
import {mount, shallow} from 'enzyme'
import sinon from 'sinon'
import { reducer as formReducer } from 'redux-form'
import { createStore, combineReducers } from 'redux'
import { Provider } from 'react-redux'
import ConnectedComponent from '../../../src/components/Component'
describe('Component <Component />', () => {
let store = createStore(combineReducers({ form: formReducer }))
let wrapper = mount(<Provider store={store}><ConnectedComponent /></Provider>)
// this call does not works
wrapper.instance().componentDidMount()
it('should load select input on component mount', () => {
expect(wrapper.find('select option')).to.have.length(12)
})
})
I was able to do like the following :
import React from 'react';
import {connect} from "react-redux";
export class Mock extends React.Component {
constructor(props) {
super(props);
}
myMethod() {
return 123
}
render() {
return (
<div>Test</div>
)
}
}
Mock = connect()(Mock);
export default Mock;
Jest test snippet :
const wrapper = mount(
<Provider store={store}>
<Mock/>
</Provider>
)
let result = wrapper.find(Mock).children().instance().myMethod();
expect(result).toEqual(123);
hope that helps someone!

Connected component not receiving store props n Redux

I was doing a bit of refactoring and tried connecting a higher level component to redux using connect() but the component I'm connecting keeps giving me empty props.
I've included the relevant code, I've structured my redux reducers into a ducks format, so the actions/creators and reducers are in one module file.
The files are containers/login.js, presentation/login.js, presentation/logins.js, app.js and the root index.js.
When I decided to rename some actions, files and reducers, moved the connect to a higher component, the connection stopped working and now I have empty props.
Help much appreciated.
// containers/login.js
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom'
import { fetchPage } from '../redux/modules/Login';
import Login from '../presentation/Login';
const mapStateToProps = (state) => {
return {
page: state.page,
forms: state.forms
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchPage: () => dispatch(fetchPage())
} // here we're mapping actions to props
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login);
// redux/modules/login.js
import fetch from 'cross-fetch';
const RECIEVE_FORM = 'RECIEVE_FORM';
export const receiveForm = (response) => ({
type: RECIEVE_FORM,
forms: response.forms
})
const initialState = {
page: "",
forms: []
}
// MIDDLEWARE NETWORK REQUEST DISPATCHER
export const fetchPage = () => {
return dispatch => {
return fetch('http://localhost:3001/login')
.then(
response => response.json(),
)
.then(
response => dispatch(receiveForm(response))
)
}
}
// REDUCER COMPOSITION CALL EXISTING REDUCERS
// REDUCER COMPOSITION PATTERN
// ACCUMULATIVE ACTION REDUCER
export default function Login(state = initialState, action){
switch (action.type){
case RECIEVE_FORM:
return {
...state,
forms: action.forms
}
default:
return state;
}
}
// presentation/login.js
import React, { Component } from 'react';
import styled from 'styled-components';
import Wrapper from '../components/Wrapper';
import Card from '../components/Card';
import Text from '../components/Text';
import Logo from '../components/Logo';
import FormGroup from '../components/FormGroup';
const WrapperLogin = styled(Wrapper)`
.login__card{
padding: 4.5rem 2.5rem 2rem 2.5rem;
}
`;
const BoxLogo = styled.div`
.login__logo{
display: block;
margin: 0 auto;
}
`;
export default class Login extends Component{
componentDidMount() {
console.log(this.props)
//this.props.fetchPage();
}
render(){
return(
<main>
<WrapperLogin className="login">
<Card className="login__card">
<BoxLogo>
<Logo className="login__logo" width={187.36} height={76.77} />
</BoxLogo>
<FormGroup name="login" className="login_formGroup" />
</Card>
<Text primitive="p" margin='4px 0 0 0' size="0.8rem" textAlign="center" display='block'>Brought to you by WORLDCHEFS</Text>
</WrapperLogin>
</main>
)
}
}
// app.js
// manage routes here
//import _ from 'lodash';
import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Redirect } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
import Login from './presentation/Login';
type Props = {
}
type State = {
mode: string
};
export default class App extends Component <Props, State> {
constructor(){
super();
this.state = {
...this.state,
mode: 'mobile'
}
}
render(){
return(
<ThemeProvider theme={{ mode: this.state.mode }}>
<Login />
</ThemeProvider>
)
}
}
// root
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './redux/configureStore';
import registerServiceWorker from './registerServiceWorker';
import App from './App';
import { injectGlobal } from 'styled-components';
import styles from './assets/styles';
const store = configureStore();
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root')
);
The reason your props in Login component are empty is because you are not actually using the connected Login container, As you have mentions its in containers/login
So in your App.js change the import of login from ./presentation/login to
import Login from '/path/to/containers/Login';
You have imported presentation component in your app.js rather than container component. Please import your container component like below
import Login from './containers/login.js';
This will solve the problem as per my understanding from your code

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

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 :)

Resources