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.
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 😂
If MyComponent gets data from the redux store, but organises it in some way first before mapping it, should that organisation be done in the component or mapStateToProps function and why?
const MyComponent = ({ data }) => {
// IN HERE?
return (
<div>
{data.map((d) => (...))}
</div>
);
};
const mapStateToProps = (state) => {
const output = state.data
// OR HERE?
return { data: output };
};
export default connect(mapStateToProps)(MyComponent);
Hello have a nice day.
i think is better have a file with all the logic to conect with redux, so every time i need to connect with redux i create a file that name is ComponentNameContainer.jsx, this file looks like that:
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import Row from '../components/Row';
import {doSomething} from '../redux/somethingActions'
// here the imports of function from your actions
export default withRouter(connect(
(state, ownProps) => {
return {
// props that u need from redux
// example: state.sessionReducer.user
}
},
{
// functions that u need from redux
//example: doSomething
}
)(Row))
i have a folder call containers to store all the container files to keep track of the components that are connected with redux.
I am new in react and trying to learn redux. I want to access the store inside a class, but it gives me an error the I cant use hook in class.
When I use this code in function (as I saw in a YouTube tutorial), it works without any problem. Here I access to counter in the store.
function App() {
const counter = useSelector(state => state.counter);
return <div>{counter}</div>;
}
but when I want to do this in class, it gives me an error that I can't use hooks in class.
So how can I access to my store either useSelector or useDispatch in class component?
As #Ying Zuo said, your method works only with Functional Components. To solve this problem:
Instead of this line:
const counter = useSelector(state => state.counter);
You define the counter state like this:
const mapStateToProps = state => ({
counter: state.counter
});
Then for dispatching you should use it like this:
const mapDispatchToProps = () => ({
increment,
decrement
});
At the end you combine everything like this:
export default connect(
mapStateToProps,
mapDispatchToProps()
)(App);
Don't forget to import increment and decrement from your action and connect from the react-redux module.
useSelector and useDispatch are React Hooks, which only work in function components.
https://reactjs.org/docs/hooks-overview.html#but-what-is-a-hook
With React Hooks, most components can and should be written with function components. If you have to write a class-based component, you can use connect from react-redux.
https://blog.logrocket.com/react-redux-connect-when-and-how-to-use-it-f2a1edab2013/
class App extends Component {
constructor(props){
super(props)
this.state = {
reduxState : {}
}
}
DummyView = () => {
const reducer = useSelector(state => state.reducer)
useEffect(() => {
this.setState({
reduxState : reducer
})
}, [])
return null
}
render(){
return(
<this.DummyView/>
)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I still have no idea how to fetch data from my action.
Here is the action:
import myConstant from './constatnts'
...
export const fetchData = {
isLoading,
isSuccess,
...
};
const isLoading = () => dispatch => {
dispatch({
type: myConstant.FETCH_LOADING,
payload: LoadingApi()
});
}
And also tried to use ES5:
function isSuccess() {
return function(dispatch){
dispatch({
type: myConstant.FETCH_DATA
payload: fetchDataApi()
});
};
}
and I have an error to get data to Redux in Component:
import {fetchData} from './myData'
componentWillMount() {
fetchData.isSuccess; // or fetchData.isLoading
}
I have got the following error:
Expected an assignment or function call and instead saw an expression
no-unused-expressions
How can I fix this?
You need to call your action using dispatch keywoard. If you want to use dispatch keyword from a react component then you need to wrap your Component with connect() function from react-redux package.
Next you will need to define at least mapStateToProps function to get data (EDIT: you do not need to include mapStateToProps :) include it only when you want to get some data back to your component), which you saved into the store by your reducer, from your redux store into your component as props.
So your code should looks like following:
import {fetchData} from './myData'
import {connect} from "react-redux";
class YourComp extends Component {
...
componentWillMount() {
this.props.dispatch(fetchData.isSuccess());
}
...
}
// this will push data from the store to your props
const mapStateToProps = state => ({
yourData: state.reducer.data
});
// besides other things, this line will push dispatch function callback into your component's props
export default connect(mapStateToProps)(YourComp);
you should be carefull with the syntax---
const mapStateToProps = state =>({
})
const mapDispatchToProps = dispatch =>({
addExpenseHandler : (expenseItemData) => dispatch(addExpenseItemData(expenseItemData))
})
I am facing a typeError which really confuses me and drives me kinda mad:
I have an car action creator:
import * as dispatchTypes from '../helper/dispatchTypes';
import { notifyBuyer } from './buyer';
export const addCar = () => async dispatch => {
const response = await fetch(someUrl, someBody)
if (response.ok) {
const car = await response.json();
dispatch({type: dispatchTypes.ADD_CAR_RESPONSE, car});
return notifyBuyer()(dispatch);
};
}
I have an action creator for notifyBuyer() within a buyer.js as well:
...
export const notifyBuyer = () => async dispatch => {
...
Finally, I am calling the notifyBuyer() within a React component as well:
import * as actions from '../../actions/buyer';
class WhateverComponent extends React.Component {
constructor(props) {
super(props);
}
doSomething = event => {
if (!event.disabled) {
this.props.notifyBuyer(event.toString());
}
};
render() {...}
}
export const StyledComponent = withStyles(styles)(WhateverComponent);
export default connect(
state => ({}),
{notifyBuyer: actions.notifyBuyer}
)(StyledComponent);
If I run the app and make the doSomething function run, I get the following error:
TypeError: _this.props.notifyBuyer is not a function
The interesting thing is:
If I remove the "import { notifyBuyer } from './buyer';" from car.js everything is fine.
But as soon the import is set in the file, the props of the Whatever-Component do not hold the notifyBuyer() function any longer and the typeError is thrown.
I think the export used in the connect function is look like wrong. Use the below sample code and check it out.
export default connect(
state => ({}),
dispatch => ({notifyBuyer: dispatch(actions.notifyBuyer)})
)(StyledComponent);