I am creating a React app with Create-React-App using Redux.
Following a tutorial, all the actions are put into 1 file:
src\action\index.js
export const fetchUser = (useCache = false) => async dispatch => { .. }
export const getUser = (useCache = false) => async dispatch => { .. }
export const fetchAlerts = (useCache = true) => async dispatch => { .. }
and then I connect them to my components using Connect:
import * as actions from "../../actions";
....
export default connect(mapStateToProps, actions)(Home);
However I would like to organize my actions into files, having a Accounts Action, and a Alerts action for this example. And I may want to call functions from each action in the 1 component.
My problem I'm having is I cant figure out how to add multiple actions into the 1 connect statment:
export default connect(mapStateToProps, actions)(Home);
The actions accepts an object or a function... Arrays dont work..
You're almost there, since you know mapDispatchToProp param of connect() can be object as well, you can always use
Object.assign({}, userAction, alertAction)
Or with object spread operator
{...userAction, ...alertAction}
To map all the actions to your Home component with redux you can do something like:
import * as actions from "../../actions";
const mapDispatchToProps = dispatch => {
return {
fetchUser: (useCache = false) => dispatch(fetchUser),
getUser: (useCache = false) => dispatch(getUser),
fetchAlerts: (useCache = true) => dispatch(fetchAlerts)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
See if this helps.
Related
I am using redux with redux-thunk middleware. The function in question makes a GET request to an API and upon response (.then()) dispatches the res to my redux store via an action.
For some reason when I pass dispatch to the parent function the function never runs. When I remove dispatch the parent function does run...(???) I have multiple other components within the same app that follow this exact same pattern successfully. For some reason this particular component is behaving in this strange way although i've triple checked and the boilerplate is all the same.
Here is my store.jsx:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import rootReducer from '../reducers/root_reducer'
const configureStore = (preloadedState = {}) =>
createStore(
rootReducer,
preloadedState,
applyMiddleware(thunk, logger)
);
export default configureStore;
my actions my_team_actions.js:
import * as APIUtil from '../util/api/my_team_api_util';
export const RECEIVE_ORG_SURVEY = "RECEIVE_ORG_SURVEY"
export const receiveOrgSurvey = survey => ({
type: RECEIVE_ORG_SURVEY,
survey
});
export const getOrganizationSurvey = () => dispatch => {
debugger
APIUtil.getOrgSurvey()
.then((res) => {
debugger
dispatch(receiveOrgSurvey(res))
})
.catch(err => console.log(err))
}
my API call my_team_api_util.js:
import axios from 'axios';
export const getOrgSurvey = () => {
return axios.get(`/api/mongo/organizations/test`)
}
component container my_team_container.jsx:
import { connect } from 'react-redux';
import MyTeam from './my_team';
import { getOrganizationSurvey } from '../../actions/my_team_actions';
const mSTP = state => {
return {
user: state.session.user,
};
};
const mDTP = dispatch => {
return {
getSurvey: () => getOrganizationSurvey(),
};
};
export default connect(mSTP, mDTP)(MyTeam);
component my_team.jsx:
import React from 'react';
class MyTeam extends React.Component {
constructor(props) {
super(props)
this.createTeam = this.createTeam.bind(this);
}
createTeam() {
this.props.getSurvey();
}
render() {
return (
<div className="my-team-frame frame">
<div className="my-team-container">
<div className="contact-data-container">
<div className="contact-data-header header">Contact a Data Scientist</div>
</div>
<div className="myteam" onClick={this.createTeam}>BUTTON</div>
</div>
</div>
)
}
}
export default MyTeam;
On the client side the my_team component renders fine and when I click the button which calls the function which will eventually dispatch my action it only seems to run when dispatch is NOT included in getOrganizationSurvey() in my_team_actions.js i.e. I hit both debuggers (and the second one with a correct res object). When dispatch is included (as shown in the snippet above) I don't hit either debuggers nor are any errors thrown.
I'm really scratching my head on this, any input is appreciated!
Thanks,
Ara
God I am a moron... XD
I said I triple checked... I should have checked 4 times! The issue was in my components container my_team_container.jsx I simply forgot to pass dispatch in the map dispatch to props object!
I fixed it by adding dispatch to the getSurvey callback...
my_team_container.jsx
import { connect } from 'react-redux';
import MyTeam from './my_team';
import { getOrganizationSurvey } from '../../actions/my_team_actions';
const mSTP = state => {
return {
user: state.session.user,
};
};
const mDTP = dispatch => {
return {
getSurvey: () => dispatch(getOrganizationSurvey()),
};
};
export default connect(mSTP, mDTP)(MyTeam);
it's funny how you can spend 2 hours on a problem, think it's hopeless and then as soon as you ask for help take another look at it and the solution just stares right back at you 😂
I have an enpoint that takes formData and API gets POST method only. When the page renders it takes the initial values but I have another form to change the parameters, once I change the params it does not send the updated values.
PS. Using Redux Create Slice here is my code;
Form Page
parametersChange = form => {
... };
formatData = data => {
return form;
};
And my createSlice Method;
export const functionName = (data = {}) => (dispatch, getState) => {
........
}));
};
this.props.getLossAvoidanceList({...data }); };
This should update my createSlice Method, however, the datain my createSlice method is always returns undefined. Where am I doing wrong ?
const mapStateToProps = (state) => ({
.....
});
const mapDispatchToProps = {
...
};
export default connect(
....
)(withRouter(LossAvoidance));
I show your code and nothing found any wrong but I think the problem is in declaration of HOC
try that way
import { compose } from "redux";
export default compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps)
)(LossAvoidance);
I would like to call 'mapdispatchtoprops' methods into the functional component. But, it is not working as expected"
I have shared some code.
I have created one functional component. here my code
loadHelpers.js
import { connect } from 'react-redux';
import {loadShowInfo,getCurrentSlug }
from '../../actions/requesthandler'
export const loadHelpers= (isManualAccess) =>{
loadShowInfo(isManualAccess)
return null
}
const mapDispatchToProps = dispatch => {
return {
loadShowInfo: (show_info_slug, modeType, season_slug) => dispatch(loadShowInfo(show_info_slug, modeType ,season_slug)),
getCurrentSlug: (currentslug,slugurl) => dispatch(getCurrentSlug(currentslug,slugurl))
}
};
export default connect(null , mapDispatchToProps)(loadHelpers);
loadShowInfo method contains multiple axios calls.
ShowInfo.js
I have called the functional method here.
import {loadHelpers} from '../common/loadHelpers'
loadDatas = (isManualAccess = false , seasonId = "") => {
this.props.loadHelpers(isManualAccess)
}
const mapDispatchToProps = dispatch => {
return {
loadHelpers: () => dispatch(loadHelpers()),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(ShowInfo)
Expected Result:
How to call the functional method into another functional component?
you need to modify loadHelpers. https://reactjs.org/docs/higher-order-components.html
I am using Redux,redux-thunk with react. I am returning an object but still getting the error.
authActions.js
export function register(){
return (dispatch)=>{
console.log("in register action");
dispatch({type:'auth_user'})
}
}
calling this action from Register.js using connect and props
import * as actions from '../actions/authActions';
class RegisterForm extends React.Component{
handleRegister = (e)=>{
e.preventDefault();
console.log("inside handle register");
console.log(this.props);
this.props.register();
}
}
var Register = connect(mapStateToProps,actions)(RegisterForm);
Error is
Actions must be plain objects. Use custom middleware for async actions.
EDIT 1
Implemented redux-thunk like below.
import thunk from 'redux-thunk';
const store = createStore(authReducer,applyMiddleware(
thunk,
loggerMiddleware
),window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
The code can be found on github using link
https://github.com/abhikulshrestha22/social-network/tree/master/client
You're using register from mapDispatchToProps:
this.props.register();
But it's just:
var Register = connect(mapStateToProps,actions)(RegisterForm);
So, calling register wouldn't work because it's in actions, actions.register:
var Register = connect(mapStateToProps,{register: actions.register})(RegisterForm);
Now, it should fix your issue.
actions/index.js
// with thunk
export const register = () => dispatch => (
dispatch({ type: 'auth_user' })
)
// without thunk
export const register = () => ({ type: 'auth_user' })
component/example.js
import React from 'react';
import { connect } from 'react-redux';
import { register } from '../actions';
const Example = ({ register }) => (
<button onClick={register}>Register</button>
)
export default connect(null, { register })(Example);
reducers/index.js
const authReducer = (state=false, {type, payload}) => {
switch(type) {
case 'auth_user': return !state;
default: return state;
}
}
There is nothing wrong with the current setup that you showed above.
I think your mapDispatchToProps may be the root cause of this problem.
You should declare your connect likes this
export default connect(
null,
{ register }
)(Register);
instead of (if I'm not wrong)
const mapDispatchToProps = dispatch => {
return {
register: () => {
dispatch(register());
}
};
};
export default connect(
null,
mapDispatchToProps
)(Register);
That's my guess. Hope this may help you.
handleRegister = (e) => {
...
this.props.dispatch(register());
}
Of course:
Apply redux-thunk middleware
In Register.js import register() action
Connect Register component to Redux store with react-redux connect()
EDIT:
If this simplified code (without mapDispatchToProps) doesn't work, something is wrong with your question.
Maybe your action payload contains something that's not a plain object? E.g. promise returned by axios?
Code Sandbox according to your question, everything seems to work fine:
https://codesandbox.io/s/j2mny6rvnv
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.