React Problem with multiple export in Class Component - reactjs

Previously in my Class Component redux connect used to look something like this. This worked without any issues.
//File: MyComponent.jsx
//in below code this.props.selectProducts is not undefined and this works fine
const mapStateToProps = null;
const mapActionsToProps = {
selectProducts
};
export default connect(
mapStateToProps,
mapActionsToProps
)(MyComponent);
After this I had to use this component called notistack to display the snackbar and I exported this as default instead of the existing redux connect. Now I am facing a issue where the props doesn't exist.
const mapStateToProps = null;
const mapActionsToProps = {
selectProducts
};
//Now this.props.selectProducts is undefined which is part of redux store
//But this.props.enqueueSnackbar("Preference saved."); this works. which is part of withSnackbar
export const ConnectedList = connect(
mapStateToProps,
mapActionsToProps
)(MyComponent);
export default withSnackbar(MyComponent);
If i make the redux connect as default I am unable to access this.props.enqueueSnackbar(). Any help would be much appreciated. Thanks

Just use withSnackbar on the component returned by connect and use that:
const ConnectedList = connect(
mapStateToProps,
mapActionsToProps
)(MyComponent);
export default withSnackbar(ConnectedList);

Related

mapDispatchToProps doesn't add actions to component

I'm tryng to use connect like in Redux docs (here) and I'm also using redux toolkit to work with redux (link)
import { connect } from 'react-redux'
import { actions } from '../../redux/actions';
import FormComponent from './Form';
const mapStateToProps = (state: any) => ({
item: 'state.item'
})
const mapDispatchToProps = { actions }
export default connect(
mapStateToProps,
mapDispatchToProps
)(FormComponent)
In my FormComponent I'm getting item props from mapStateToProps but actions are not passed down
My actions look like this
import { createAction } from '#reduxjs/toolkit';
const registerUser = createAction<Object, 'REGISTER_USER'>('REGISTER_USER');
export const actions = {
registerUser
}
And if I do console.log(actions) it is an object with function.
All the help will be appreciated.
This line:
mapDispatchToProps = { actions }
Is the equivalent to:
mapDispatchToProps = {
actions: {
registerUser
}
}
As per the docs bindActionCreators expects an object hash of action creators. In this example, you have nested yours under an actions property which (based on the source) will result in them being excluded from the returned props.
If you want the actions to be accessible directly from props then you can set mapDispatchToProps = actions, or just pass actions directly into connect e.g.
connect(mapStateToProps, actions)(FormComponent)

How to replace bindActionCreators and to use mapDispatchToProps and mapStateToProps

We are calling an API using bindActionCreators and every time I need to use this.props to post and to get data.
The problem is that I need to store the response data in some variable and access it through this.props.variable. For example:
export default withStyles(styles, { withTheme: true })(connect(
state => state.sensi,
dispatch => bindActionCreators(actionCreators, dispatch)
)(FetchSensi));
How can I do it?
mapStateToProps
const mapStateToProps = state => ({
variableName: state.someVariableFromState
});
and i don't use mapDispatchToProps, i pass directly action to connect like this
import {action1, action2} from './someActionFolder';
export default connect(mapStateToProps, {action1, action2})(YourComponent);
and inside your component you can use your actions like
this.props.action1();
this.props.action2();
you can also combine all your actions like
import * as actions from './yourActionsFolder';
export default connect(mapStateToProps, actions);

this.props... is not a function react react-redux

I have a problem with dispatching a action from componentDidMount...
error is : TypeError: this.props.postDetails is not a function
Action.js
export const postDetails = data => ({
type: "POST_DETAILS",
post: data
})
Container/GetDetails.js
import Details from '../components/Details'
import { postDetails } from '../actions'
const mapStateToProps = state => ({ post: state.post });
const mapDispatchToProps = dispatch => bindActionCreators({postDetails}, dispatch);
const GetDetails = connect(
mapStateToProps,
mapDispatchToProps
)(Details)
export default GetDetails
Component/Details.js
import React from 'react'
import { postDetails } from '../actions'
class Details extends React.Component {
constructor(props){
super(props);
}
componentDidMount() {
console.log("did mount details");
this.props.postDetails();
}
render() {
return (
<div>
Details page
</div>
)
}
}
export default Details;
Can someone help me? Why i have this error?
In App.js (or wherever you are importing the Details component), are you using the path to your GetDetails container (not component)?
I moved state from a component to a container and forgot to update the import path which gave me this same error. Updating the import path to the container took care of it.
Edit:
For example, I have an apiLanding folder that has apiLanding.js (the component) and apiLanding-container.js (the container).
In my app.js, I needed to change
import apiLanding from './components/apiLanding/apiLanding';
to
import apiLanding from './components/apiLanding/apiLanding-container';
That way, the app now has access to the redux state and actions. This was a silly mistake and may not be your issue, but wanted to share just in case the import path was overlooked.
You have to return an object, where the keys are your props. See docs.
const mapDispatchToProps = dispatch => ({ postDetails: bindActionCreators({postDetails}, dispatch) })
Or, you can use the shorthand notation:
const GetDetails = connect(
mapStateToProps,
{ postDetails }
)(Details)
I don't see bindActionCreator imported. Use eslint to get rid of these errors
There are two things which don't really seem right to me. Personally I never used bindActionCreators. I would just create my mapDispatchToProps as following:
const mapDispatchToProps = dispatch => {
return {
postDetails: () => dispatch(actions.postDetails)
};
};
But also your postDetails call expects an argument, which you should add in your function call. So your mapDispatchToProps would look like this:
const mapDispatchToProps = dispatch => {
return {
postDetails: (data) => dispatch(actions.postDetails(data))
};
};
Also you're importing your action as postDetails. Are you sure that this is just one action? And not a combination of all actions in your file? Note how I added your function as actions.postDetails instead of just postDetails.

Multiple actionCreators in single component

I want to have multiple actionCreators dispatched into one component. I know you can do this with state
export default connect(
(state: ApplicationState) => Object.assign({}, state.search, state.resources),
ResourcesState.actionCreators// i have another actionCreator I want to add
)(Home) as typeof Home;
But not sure the syntax to do this with actionCreators. I have read into
mapDispatchToProps
But not sure how to implement.
There are a few ways to set up dispatching of Redux actions in React components:
Use connect(mapState)(MyComponent). By default, your component will be given props.dispatch, and you can call props.dispatch({type : "SOME_ACTION"}).
Pass a mapDispatchToProps function as the second argument to connect. Inside, you can create new function references that call dispatch:
function mapDispatchToProps(dispatch) {
return {
addTodo : (text) => dispatch({type : "ADD_TODO", text})
}
}
You can also use the Redux bindActionCreators utility instead:
function mapDispatchToProps(dispatch) {
return bindActionCreators({addTodo, toggleTodo}, dispatch);
}
Finally, you can pass an object full of action creators directly to connect:
const actions = {addTodo, toggleTodo};
export default connect(mapState, actions)(MyComponent);
I highly recommend the fourth approach, which I also talk about in my blog post Idiomatic Redux: Why Use Action Creators?.
mapDispatchToProps is the second argument in connect. So for example:
import customAction from 'actions-directory-in-your-app'
const mapStateToProps = () => {} // no implementing anything for example purposes
const mapDispatchToProps = () => ({ customAction })
const ConnectedContainer = connect(
mapStateToProps,
mapDispatchToProps
)(YourContainer)
customAction becomes now a prop in YourContainer so you can use it the same way other props within your component.
the Second argument to connect takes an object or a function so you can add
export default connect(
(state: ApplicationState) => Object.assign({}, state.search, state.resources),
{
ResourcesState.actionCreators,
some_other_action_creators,
some_more
}
)(Home) as typeof Home;
Also read through this answer on Stackoverflow for more information on how to use action creators
Why is there no need for a mapDispatchToProps function here?
The second argument to connect takes an object, so you can use of ES6 syntax and avoid the use of mapDispatchToProps.
import { yourAction } from './your_actions_folder'
class Home extends Component{
....
//For dispatch a action you only call the action Creator
this.props.yourAction()
}
export default connect(mapStateToProps,{yourAction})(Home)

Map redux dispatch to redux-form

Sorry if this has been answered elsewhere, I'm a Redux beginner, and I couldn't find anything related.
I'm having trouble mapping dispatch to ReduxForm. Im setting up my reducers like this:
import { reducer as formReducer } from 'redux-form';
import foo from './foo';
import bar from './bar';
const rootReducer = combineReducers({
foo,
bar,
form: formReducer
});
export default rootReducer;
and then combining them like so:
import rootReducer from '../reducers/index';
const loggerMiddleware = createLogger();
const createStoreWithMiddlware = applyMiddleware(
thunkMiddleware,
loggerMiddleware
)(createStore);
export default function configureStore(initialState) {
const store = createStoreWithMiddlware(rootReducer, initialState);
return store;
}
and then mapping dispatch to props like this:
function mapStateToProps(state) {
return {
foo: state.foo,
bar: state.bar
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
And then I have a form component that I am wrapping in a reduxForm like this:
TestForm = reduxForm({
form: 'testForm',
fields: ['firstName', 'lastName', 'email']
})(TestForm);
export default TestForm;
But I get an error:
Warning: Failed propType: Required prop dispatch was not specified in ReduxForm(TestForm). Check the render method of TestFormParent.
What is the best way to inject dispatch into a form component?
Turns out the docs on npm are a little bit different, and more complete. If anyone else runs into this issue, use connectReduxForm instead of reduxForm solved the problem.
reduxForm works for version 4 of redux-form

Resources