Unable to connect dispatch to props - reactjs

I have a class component that I want to connect to the store in order to pull data.
I have tested the action with a function component and it was working well. Due to some limitations, I decided to use a class component.
The problem is that 'getTableDataAction' does not exist despite the fact that I did connect the dispatch via connect function.
As a result I will get the foolowing error:"TypeError: this.props.getTableDataAction is not a function"
export default class TchExportButton extends Component {
constructor(props) {
super(props);
this.state = {
selectedIndex: 0,
anchorEl: null,
options: ['Select drill down report',
'Destroyed DCA',
'Repaired - A008']
}
}
componentDidUpdate(prevState) {
if (this.state.selectedIndex !== prevState.selectedIndex) {
if (this.state.selectedIndex > 0) {
this.props.getTableDataAction(this.state.selectedIndex)
}
}
}
.....
...
..
const mapStateToProps = (state) => {
return {
data: state.tchCommecialTableData.data,
}
}
const mapDispatchToProps = (dispatch) => {
return {
getTableDataAction: (buttonId) => dispatch(engineeringDataAction.getTableDataAction(buttonId))
}
}
connect(mapStateToProps, mapDispatchToProps)
I am not sure what I am doing wrong but something is missing there and I can't find the root cause.
Any idea what is wrong?
Thank you

Your default export should be the connected component, not the unconnected component.
export default connect(mapStateToProps, mapDispatchToProps)(TchExportButton);
(Make sure to remove the export default at the top)

Define class and export connect(class):
class TchExportButton extends Component
export:
export default connect(mapStateToProps, mapDispatchToProps)(TchExportButton)

To add to what the other guys have answered, connect is a function that returns a function which in turn returns a component. In react-redux, connect is probably something like this:
function connect(mapStateToProps, mapDispatchToProps, ...other arguments){
return function(Component){
...
}
}
It's definitely more complicated than this but this is the core concept of calling
connect(mapStateToProps, mapDispatchToProps)(Component)
as the first function call calls the first function and the second calls the returned function.

Related

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.

Retrieving a Redux state, but also change another Redux state in same React Native component?

I have a React component that currently just retrieves a state from Redux. Here is the general layout:
const mapStateToProps = state => {
return { stuff: state.stuff };
};
class MyComponent extends React.Component {
// use 'stuff' from redux to build the Views
}
export default connect(mapStateToProps)(MyComponent);
But now, what if I want to add a button that changes another Redux state called other?
To save the new Redux state, I know we have to create a dispatch to the action. ie,
const mapDispatchToProps = dispatch => {
....
};
Then finally connect them:
connect(null, mapDispatchToProps)(MyComponent);
But my confusion is if I am already connecting with mapStateToProps, how can I also map it to mapDispatchToProps so that I can update the Redux state in the same component?
You can use both ;-)
For example :
Action.js
export const textChanged = (newText) => {
return { type: "TEXT_CHANGED", newText }
};
HomeScene.js :
import { textChanged } from "../actions;
...
render () {
const { myText } = this.props;
<TextInput
value={myText}
onChangeText={(newText) => this.props.textChanged(newText)}
/>
}
function mapStateToProps(state) {
return {
myText: state.appContent.myText
};
}
export default connect(mapStateToProps, { textChanged })(HomeScene);
Reducer.js
case "TEXT_CHANGED":
return {
...state,
myText: action.newText
};
Hope it helps !
Hm, looks like I asked too early. I did a bit of reading and the parameters in connect() actually accepts both.
So like this:
connect(mapStateToProps, mapDispatchToProps)(MyComponent)

dispatch is not defined on my functions using react and redux

I am trying to use react-redux-loading-bar to show a loading bar during fetching data from API servers, I don't use promise middleware so I decided to use it without, the example says do this
import { showLoading, hideLoading } from 'react-redux-loading-bar'
dispatch(showLoading())
// do long running stuff
dispatch(hideLoading())
And it gives me this.
Uncaught ReferenceError: dispatch is not defined
I had similar issues with other libraries and gave up that time, this time I want to actually understand how this works, so any info is greatly appreciated. Heres the code that causing the error, speicifc function and class names stripped.
import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { showLoading, hideLoading } from 'react-redux-loading-bar'
import * as xxxxxActions from '../../actions/xxxxx'
class xxxxxx extends React.Component {
constructor(props) {
super(props)
this.handleclick = this.handleclick.bind(this)
}
handleclick(){
dispatch(showLoading())
asynchronousGetFunction( target_url, function (data) {
dispatch(hideLoading())
})
}
render() {
return <li onClick={this.handleclick}>yyyyyyy</li>
}
}
function mapStateToProps( state ){
return {
}
}
function mapDispatchToProps(dispatch, state) {
return {
xxxxxActions: bindActionCreators( xxxxxActions, dispatch )
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(xxxxxx)
Once you connect your component, dispatch becomes a prop. The same applies for xxxxxActions...
In that case, the handle would be:
handleclick(){
this.props.dispatch(...)
}
You need to pass dispatch function to your props:
function mapDispatchToProps(dispatch, state) {
return {
xxxxxActions: ....,
showLoading: function () {
dispatch(showLoading());
},
hideLoading: function () {
dispatch(hideLoading());
},
};
}
Then, use it in your component:
this.props.showLoading();
...
this.props.hideLoading();
You don't need use "dispatch" in components. Bind your functions with dispatch in mapDispatchToProps.
Read more about mapDispatchToProps.

React-Redux reducer method errors out when executed

I am working on a first React-Redux app. I have the following container:
import { connect } from 'react-redux'
import Visualization from '../components/visualization'
// http://redux.js.org/docs/basics/UsageWithReact.html#implementing-container-components
const mapStateToProps = (state) => state; // identity transform, for now...
function mapDispatchToProps(dispatch) {
return {
stepForward: () => dispatch('STEP_FORWARD')
};
}
const VisualizationContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Visualization);
export default VisualizationContainer;
And the following subsequent component:
import React from 'react'
export default class Visualization extends React.Component {
render() {
console.log(this.props.stepForward());
return <div>"HELLO WORLD"</div>;
}
}
However, when I run this application I error out with:
Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
The problem, marked with XXX, is that stepForward exists, but explodes when executed. What is the error here?
It is just as the error says. An action should be an object and no other type. You're trying to dispatch a string as an action, which is invalid. Instead, you should use an object with a type property set to the action's type string.
Change your mapDispatchToProps function to:
function mapDispatchToProps(dispatch) {
return {
stepForward: () => dispatch({
type: 'STEP_FORWARD'
})
};
}
and it should work.
You should actually go a bit further than that and make all your actions follow a standardized template. A nice one a lot of React devs follow is flux-standard-action.

React-redux doesn't set mapDispatchToProps into props

Can you help to undestand why my container doesn't transfer dispatch prop saveInfo into component?
My container:
import { connect } from 'react-redux'
import AddCarWashForm from './../components/carwash/subComponents/AddCarWashForm.jsx'
import {addInfo} from './../actions'
const mapDispatchToProps = (dispatch) => {
return {
saveInfo: (info) => {
dispatch(addInfo(info))
}
}
}
const AddCarWashFormContainer = connect(
null,
mapDispatchToProps
)(AddCarWashForm)
export default AddCarWashFormContainer
Here is part of AddCarWashForm.jsx
export default class AddCarWashForm extends React.Component{
static contextTypes = {
saveInfo: React.PropTypes.func.isRequired
};
And when I execute this code, I see in console: Warning: Failed context type: Required context 'saveInfo' was not specified in 'AddCarWashForm'.
You're mapping to props, not to context. Define it as a propType instead and it'll work as you expect it.

Resources