material-ui withStyle not working with resux-form - redux

I'm currently working on my first real React-Redux app (ReactDom to be exact).
The app is using material ui (I'm not the project manager)
I'm having trouble applying style to a component exported via reduxForm.
my code:
import React, {Component} from 'react';
import {withStyles} from '#material-ui/core/styles/withStyles';
import { TextField } from '#material-ui/core';
import { Field, reduxForm} from 'redux-form';
import {connect} from 'react-redux';
import { some acttions } from '../actions';
const styles = (theme) => ({});
const mapStateToProps = (state) => ({});
const mapDispatchToProps = (dispatch) => ({
some: () => dispatch(some(data)),
actions: () => dispatch(actions())
})
class FormComponent extends Component {
// Component with form
}
FormComponent = connect(
mapStateToProps,
mapDispatchToProps
)(withStyles(styles)(FormComponent));
export default reduxForm({
form: 'myForm'
})(FormComponent);
This results in TypeError: Object(...) is not a function pointing to the command with connect. When I erase withStyle, it doesn't break, but looks bad.
Thanks in Advance,
Gal

Related

Why this error is coming TypeError: Cannot read property 'type' of undefined

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;
};

Trying to create simple component with React-JSS

I'm trying to create a simple component, styled with React-JSS:
import React from 'react';
import { createUseStyles, useTheme } from 'react-jss';
import { useSessionState, useSessionDispatch } from '../../../contexts/SessionContext';
const useStyles = createUseStyles({
messageSuccess: {
backgroundColor: 'green'
}
});
const SystemMessage = () => {
const dispatch = useSessionDispatch();
const theme = useTheme();
const classes = useStyles({theme});
return (
<div className={classes.messageSuccess}>
abcd
</div>
);
}
export default SystemMessage;
Upon running it, I get this message:
TypeError: Object(...) is not a function
const useStyles = createUseStyles({
What am I doing wrong?
You should update your react-css version to 10.0.0

Rerendering on async fetch with react-mobx

I'm trying to use mobx-rest with mobx-rest-axios-adapter and mobx-react, and I have trouble making the component rerender upon async data retrieval.
Here's my data model, in state/user.js:
import { Model } from 'mobx-rest';
class User extends Model {
url() {
return '/me';
}
}
export default new User();
This is the React component, in App.js:
import React from 'react';
import { inject, observer } from 'mobx-react';
import { apiClient } from 'mobx-rest';
import createAdapter from 'mobx-rest-axios-adapter';
import axios from 'axios';
import { compose, lifecycle, withProps } from 'recompose';
const accessToken = '...';
const API_URL = '...';
const App = ({ user }) => (
<div>
<strong>email:</strong>
{user.has('email') && user.get('email')}
</div>
);
const withInitialise = lifecycle({
async componentDidMount() {
const { user } = this.props;
const axiosAdapter = createAdapter(axios);
apiClient(axiosAdapter, {
apiPath: API_URL,
commonOptions: {
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
});
await user.fetch();
console.log('email', user.get('email'));
},
});
export default compose(
inject('user'),
observer,
withInitialise,
)(App);
It uses recompose to get the user asynchronously from an API in componentDidMount(), and once available the component is supposed to show the user email. componentDidMount() prints the email once available.
Finally this is index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Provider } from 'mobx-react';
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';
import { Router } from 'react-router';
import App from './App';
import { user } from './state/user';
const documentElement = document.getElementById('ReactApp');
if (!documentElement) {
throw Error('React document element not found');
}
const browserHistory = createBrowserHistory();
const routingStore = new RouterStore();
const stores = { user };
const history = syncHistoryWithStore(browserHistory, routingStore);
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<App />
</Router>
</Provider>,
documentElement,
);
My problem is that the component doesn't rerender once the user is retrieved and the email is available, although the console log shows that it is returned ok in the async request. I've tried playing around with mobx-react's computed, but no luck. Any ideas?
I think it will work if you change your compose order of App.js:
export default compose(
inject('user'),
withInitialise,
observer,
)(App);
According to the MobX official document,
Tip: when observer needs to be combined with other decorators or
higher-order-components, make sure that observer is the innermost
(first applied) decorator; otherwise it might do nothing at all.

Why am i getting "Error: Actions must be plain objects. Use custom middleware for async actions." error?

I am continuously getting " Actions must be plain objects. Use custom middleware for async actions." error and I am totally stuck here. What am I doing wrong here please help me figure out and help me get out of this error.
This is my index.js file where I have integrated redux store to the app.
import "babel-polyfill";
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux'
import { composeWithDevTools } from 'redux-devtools-extension';
import { createStore, applyMiddleware, combineReducers, compose} from 'redux'
import createSagaMiddleware from 'redux-saga'
import rootSaga from './sagas'
import { postsReducer } from './reducers/posts'
import Routes from './routes';
import './styles/style.css'
const rootReducer = combineReducers({ postsReducer })
const sagaMiddleware = createSagaMiddleware()
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(sagaMiddleware)))
sagaMiddleware.run(rootSaga)
ReactDOM.render((
<Provider store={store}>
<Router><Routes /></Router>
</Provider>
), document.getElementById('root'))
this is my saga.js
import { take, put, call, fork, select, takeEvery, all, takeLatest } from 'redux-saga/effects'
import PostApi from './api/postApi';
import { gotPosts } from './actions/celebrity';
import { POSTS } from '../types'
export function* getAllPosts () {
const posts = yield call(PostApi.getPosts, {})
console.log('postssss', posts)
yield put(gotPosts(posts.data))
}
export function* watchGetPosts () {
yield takeLatest(POSTS, getAllPosts)
}
export default function* root() {
yield all([ fork(watchGetPosts) ])
}
this is my action.js
import { POSTS } from '../../types';
export const gotPosts = (data) => {
return {
type: POSTS,
data,
}
}
export const getPosts = () => dispatch => {
dispatch(gotPosts);
}
this is component page where i dispatched action.
import React, { Component } from 'react';
import { Card, Row, Col } from 'antd';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux'
import { getPosts } from '../actions/celebrity';
const { Meta } = Card;
class MainPage extends Component {
componentDidMount () {
console.log(this.props)
this.props.getPosts();
}
render() {
return <Row type="flex" className="main" justify="center" align="between">
......
</Row>
}
}
const mapStateToProps = state => {
return {
posts: state.postsReducer
}
}
const mapDispatchToProps = dispatch => ({
getPosts: () => {
dispatch(getPosts());
},
});
export default connect(mapStateToProps, mapDispatchToProps)(MainPage);
postsReducer
export const postsReducer = (state = [], action) => {
console.log(action)
switch(action.type){
case POSTS:
return action.data;
default:
return state;
}
}
You can't dispatch function w/o middleware support.
Problem originates from mapDispatchToProps:
{
getPosts: () => { dispatch(getPosts()); }
}
tracing down to your actions.js, getPosts() returns dispatch => dispatch(gotPosts), which is actually a function not an action(plan javascript object), redux dispatch by default doesn't recognize functions, unless you use middleware to enhance it, redux thunk for example.
Since you already have redux saga for async flow, simply dispatch an action from mapDispatchToProps should be fine, also consider create separate actions to differentiate POSTS_REQUEST, POSTS_RECEIVE, POSTS_FAILURE if possible.
import {POST} from '....../actionTypes'
...
{
getPosts: () => { dispatch({ type: POST }); }
}

No reducer provided for key "dashboard"

when i tried user store in my test
import React from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import chai from 'chai';
import App from '../layouts/App';
import store from '../redux/configureStore';
const expect = chai.expect;
// let store;
let app;
describe('login', () => {
beforeEach(() => {
app = mount (
<Provider store={store}>
<App />
</Provider>
)
})
but i got No reducer provided for key "dashboard"
here is my configStore main code
const reducer = {
dashboard,
PageLogin,
};
const store = createStore(
reducer,
composeEnhancers(applyMiddleware(sagaMiddleware))
);
I got PageLogin, but can't got dashboard
and there is dashboard main code
export {
snackbarActions,
dialogActions,
userConfigActions,
authActions,
progressActions,
UserProfileActions,
// ...
};
You need to use combineReducers to combine your reducers
import { combineReducers } from 'redux'
const reducer = combineReducers({
dashboard,
PageLogin,
})

Resources