I am setting up a simple React/Redux app. Here is my setup:
var {createStore, applyMiddleware } = require('redux')
var thunkMiddleware = require('redux-thunk')
var store = createStore(
reducers,
applyMiddleware(thunkMiddleware)
)
class App extends React.Component {
render() {
return (
<Provider store={store}>
<HashRouter>
<div className="app">
<Route exact path='/' component={Home}/>
<Route path='/Test' component={Test}/>
</div>
</HashRouter>
</Provider>
);
}
}
Also, here are my reducers:
var {combineReducers} = require('redux')
const carlist = (state=[], action) => {
switch (action.type){
case 'LOAD':
return action.test
default:
return state
}
}
module.exports = combineReducers({carlist})
When I run my app, I get this error:
applyMiddleware.js:39 Uncaught TypeError: middleware is not a function
What am I missing?
the problem looks like it might be here:
var thunkMiddleware = require('redux-thunk')
Your middleware -- here thunkMiddleware -- is not a function, suggesting that it is not being pulled from the package. You should try:
var thunkMiddleware = require('redux-thunk').default
Or, try using ES6 module syntax (since you are already using ES6 features):
import thunkMiddleware from 'redux-thunk'
I had this error when using redux-logger
I had just upgraded my packages and change
import createLogger from 'redux-logger'
to
import { createLogger } from 'redux-logger'
Related
I am migrating from my Create React App (client-side-rendering) to Next JS (server-side rendering) due to SEO reasons. Migrating was going well until using React-Redux-Firebase / Firestore. This is the page I am trying to load:
Discover.js
import React, { Component } from 'react'
import { firestoreConnect, isEmpty } from 'react-redux-firebase';
import { compose } from 'redux'
import { connect } from "react-redux";
import { blogpostsQuery } from '../blogposts/blogpostsQuery';
import DiscoverList from "./DiscoverList";
const mapState = (state, ownProps) => {
let blogposts = {};
blogposts =
!isEmpty(state.firestore.ordered.blogposts) &&
state.firestore.ordered.blogposts;
return {
blogposts,
};
};
class DiscoverPage extends Component {
render() {
const {blogposts} = this.props
return (
<div className="container">
<div className="hero">
<h1>Discover stories</h1>
<p className="lead">Blogpost published:</p>
</div>
<DiscoverList blogposts={blogposts} />
</div>
)
}
}
export default compose(
firestoreConnect(() => blogpostsQuery()),
connect(mapState, null)
)(DiscoverPage)
The error I received is this:
ReferenceError: XMLHttpRequest is not defined
at Rn.ca (/Users/fridovandriem/timepath/node_modules/firebase/firebase-firestore.js:1:36966)
at Ie (/Users/fridovandriem/timepath/node_modules/firebase/firebase-firestore.js:1:18723)
at Se (/Users/fridovandriem/timepath/node_modules/firebase/firebase-firestore.js:1:18385)
at Kn.a.Ia (/Users/fridovandriem/timepath/node_modules/firebase/firebase-firestore.js:1:39600)
at jt (/Users/fridovandriem/timepath/node_modules/firebase/firebase-firestore.js:1:15360)
error Command failed with exit code 1.
I wasn't the only one with this problem and I have found the solution on GitHub by prescottprue:
https://github.com/prescottprue/react-redux-firebase/issues/72
Including documentation: http://react-redux-firebase.com/docs/recipes/ssr.html
// needed to fix "Error: The XMLHttpRequest compatibility library was not found."
global.XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
The problem is (sorry i am new developer) I have no idea where to add this line of code? Adding it to _app.js doesnt work.. i've added https://www.npmjs.com/package/xmlhttprequest but still no luck...
-app.js
import App from "next/app";
import { Provider } from "react-redux";
import React, { Fragment } from "react";
import withRedux from "next-redux-wrapper";
import "../src/styles.css";
import configureStore from "../src/app/store/configureStore";
import Header from "../src/app/layout/Header";
import NavBar from "../src/app/layout/nav/Navbar/NavBar";
import Footer from "../src/app/layout/Footer";
global.XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
//Anything returned here can be accessed by the client
return { pageProps: pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<Fragment>
<Header />
<NavBar />
<Provider store={store}>
<Component {...pageProps} />
</Provider>
<Footer />
</Fragment>
);
}
}
export default withRedux(configureStore)(MyApp);
Could somebody help me?
Many thanks
Frido
How to solve this error TypeError: Cannot read property 'type' of undefined.
I am very new to react-redux and redux, simply I am trying to do state management through redux.
For this I installed react-redux and redux npm packages. And I created a store, In store a have reducer.js file. Even I imported Provider and store in index.js. Help to resolve this issue.
In store folder I have reducer.js file
This is reducer.js file code
const initialState = {
age: 21
}
const reducer = (state = initialState, action) => {
const newState = {state};
if(action.type === 'AGE_UP') {
newState.age++
}
if(action.type === 'AGE_DOWN') {
newState.age--
}
return newState;
};
export default reducer
This is App.js
import React, { Component } from 'react';
import './App.css'
import { connect } from 'react-redux'
class App extends Component {
render() {
return (
<div className='App'>
<div>Age: <span>{this.props.age}</span></div>
<button onClick={this.props.onAgeUp}>Age UP</button>
<button onClick={this.props.onAgeDown}>Age Down</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
age:state.age
}
}
const mapDispatchToProps = (dispatch) => {
return {
onAgeUp: () => dispatch({type: 'AGE_UP'}),
onAgeDown: () => dispatch({type: 'AGE_DOWN'})
}
}
// export default connect()(App)
export default connect(mapStateToProps,mapDispatchToProps) (App)
This is index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reducer from './store/reducer';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import * as serviceWorker from './serviceWorker';
const store = createStore({}, reducer);
ReactDOM.render(<Provider projectStore={store}><App></App></Provider>, document.getElementById('root'));
serviceWorker.unregister();
I can see multiple issues in your code:
createStore takes reducer as the first argument, look at API documentation, try this:
const store = createStore(reducer);
Provider has prop store and not projectStore, look at API documentation, try this:
ReactDOM.render(<Provider store={store}><App></App></Provider>, document.getElementById('root'));
You probably mutate your state in a reducer, try this:
const reducer = (state = initialState, action) => {
// it is better to use switch instead of if in reducer, for sake of readability
switch (action.type) {
case 'AGE_UP':
// it is better to have return statement here, it is more robust to developer errors
// it is better to use object spread and return result here than creating `newState` variable, you will do less errors
return {...state, age: state.age + 1}
case 'AGE_DOWN':
return {...state, age: state.age - 1}
}
return state;
};
I am trying to connect some component (USERS) to my store. I will show you each step.
First of all i create my store in index.js:
// composeWithDevTools helps to follow state changes, remove in production
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducers, composeEnhancers(applyMiddleware(sagaMiddleware)));
//sagaMiddleware.run(usersSaga);
console.log('MYSTORE: ', store);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
My reducer is coded in the following way:
import { combineReducers } from 'redux';
import usersReducer from './usersReducer';
export default combineReducers({
users: usersReducer,
});
Now my App.js file looks like this:
import React from 'react';
import { HashRouter, Route, Redirect } from 'react-router-dom';
import { AuthorisationMails } from './route-components/AuthorisationMails.js';
import { ChangePassword } from './route-components/ChangePassword.js';
import { Credits } from './route-components/Credits.js';
import { Graphs } from './route-components/Graphs.js';
import { Groups } from './route-components/Groups.js';
import { HeaderBar } from './components/HeaderBar.js';
import { Home } from './route-components/Home.js';
import { Login } from './route-components/Login.js';
import { MailServers } from './route-components/MailServers.js';
import { MailStatus } from './route-components/MailStatus.js';
import { Options } from './route-components/Options.js';
import { StatusMails } from './route-components/StatusMails.js';
import { Users } from './route-components/Users.js';
const App = () => (
<div>
<HashRouter>
<HeaderBar />
<Route path="/">
<Redirect to="/login" />
</Route>
<Route path="/login" component={Login} />
<Route path="/dashboard_user" component={Users} />
</HashRouter>
</div>
);
export default App;
In Users, i try to connect to the store with a mapstateToProps and connect as you see here:
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../redux/actions';
export class Users extends Component {
componentDidMount() {
console.log('USERPROPS: ', this.props);
}
render() {
return <div>Users</div>;
}
}
const mapStateToProps = state => {
console.log('USERSSTATE: ', state.user);
return {
users: state.userReducer,
};
};
export default withRouter(connect(mapStateToProps)(Users));
The problem here is that somehow i am connecting in the wrong way, since the console.log of USERPROPS does not contain a property user. It contains history location and match.
I tried connecting by using the following url https://react-redux.js.org/api/connect.
Any idea on why my component is not connecting to the store?
Solved it, i removed the brackets when importing components, thus for example:
import { Credits } from './route-components/Credits.js' => import Credits from './route-components/Credits.js'
I think you might need to use state.users.user:
const mapStateToProps = state => {
return {
users: state.users.user,
};
};
I upgraded meteor and I started receiving deprecation warning for createContainer(). As a result, I've tried to implement withTracker however now I'm getting Component(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.. I'm not sure what I'm missing here, can someone point out my error.
Path: App.jsx
import { Meteor } from 'meteor/meteor';
import React from 'react';
import PropTypes from 'prop-types';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { withTracker } from 'meteor/react-meteor-data';
// IsCandidate Spefic Routes
import TestContainer from '../../containers/candidate/TestContainer';
const App = appProps => (
<Router>
<ScrollToTop>
<div className="bgColor">
<NavBar {...appProps} />
<Grid className="main-page-container">
<Switch>
{/* candidate routes */}
<IsCandidate exact path="/candidate/testpage/:id" component={withTracker(TestContainer)} {...appProps} />
{/* IsPublic routes */}
<Route render={function () {
return <p>Page not found</p>;
}}
/>
</Switch>
</Grid>
</div>
</ScrollToTop>
</Router>
);
App.propTypes = {
loggingIn: PropTypes.bool,
isCandidate: PropTypes.bool
};
export default createContainer(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
isCandidate: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isCandidate'),
};
}, App);
Path: IsCandidate.jsx
import React from 'react';
import PropTypes from 'prop-types'; // ES6
import { Route, Redirect } from 'react-router-dom';
const IsCandidate = ({ loggingIn, isCandidate, component: Component, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (loggingIn) return <div />;
return isCandidate ?
(<Component loggingIn={loggingIn} isCandidate={isCandidate} {...rest} {...props} />) :
(<Redirect to="/login" />);
}}
/>
);
IsCandidate.propTypes = {
loggingIn: PropTypes.bool,
isCandidate: PropTypes.bool,
component: PropTypes.func
};
export default IsCandidate;
Path: Testcontainer.jsx
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
import { Test } from '../../../api/test/test';
import TestPage from '../../pages/candidate/TestPage';
export default TestContainer = withTracker(({ match }) => {
const testHandle = Meteor.subscribe('test', match.params.id);
const loadingTest = !testHandle.ready();
const testCollection = Test.findOne(match.params.id);
const testExist = !loadingTest && !!testCollection;
return {
loadingTest,
testExist,
testCollection: testExist ? testCollection : {}
};
}, TestPage);
Update
export default withTracker(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
isCandidate: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isCandidate'),
isEmployer: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isEmployer'),
isAdmin: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isAdmin')
};
})(App);
In App.jsx you import withTracker but use createContainer.
withTracker takes only one argument (your reactive function) and wraps your child component where createContainer took 2 arguments (function and component).
createContainer(fn, C);
withTracker(fn)(C);
EDIT
Remove the withTracker call in App.js from this line:
<IsCandidate exact path="/candidate/testpage/:id" component={withTracker(TestContainer)} {...appProps} />
so it becomes
<IsCandidate exact path="/candidate/testpage/:id" component={TestContainer} {...appProps} />
How about it?
This is how I create my store
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux';
import rootReducer from '../reducers';
const debugware = [];
if (process.env.NODE_ENV !== 'production') {
const createLogger = require('redux-logger');
debugware.push(createLogger({
collapsed: true
}));
}
export default function configureStore(history, initialState) {
const store = createStore(
rootReducer,
initialState,
window.devToolsExtension ? window.devToolsExtension() : f => f,
applyMiddleware(thunkMiddleware, routerMiddleware(history), ...debugware),
);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers/index').default;
store.replaceReducer(nextRootReducer);
});
}
return store;
}
But my app stop working and I can find why. Any suggestion please.
You can try this:
import { createStore, applyMiddleware, compose } from 'redux';
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(thunkMiddleware, routerMiddleware(history), ...debugware),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
);
The DevTools' enhancer should be always the last in compose, so it will know about other middlewares and enhancers.
Additionally, in case you want to dispatch actions remotely, you should also add:
if (window.devToolsExtension) window.devToolsExtension.updateStore(store)
As indicated in troubleshooting.