React use redux action don't work In own module - javascript

This my util module, and when I use redux action it does not work.
import {openloading} from '../actions/loading'
export default function (e) {
openloading(e.font);
}
But in my react component it does work

Actions themselves do nothing, which is ironic given the name. Actions merely describe what is going to happen and how state will change. Change actually occurs when these instructions are dispatched to the reducer. As Paul said, you need access to the dispatch method.
Typically, you're calling your util module functions from within your components. In that case, you might want to pass the dispatch method as a parameter.
import { openloading } from '../actions/openloading'
export const myFn = (e, dispatch) => {
dispatch(openloading(e.font))
}
Your component should get wired up to Redux like so:
import React from 'react'
import { connect } from 'react-redux'
import { myFn } from 'somewhere'
const myComponent = ({ dispatch }) => {
myFn(e, dispatch)
return (
<div>
{ ...whatever }
</div>
)
}
const mapStateToProps = (state) => {
return { ...stuff }
}
const mapDispatchToProps = (dispatch) => {
return {
dispatch: dispatch
}
}
export default connect(mapStateToProps, mapDispatchToProps)(myComponent)
Note that dispatch is getting passed into the component as a prop in mapDispatchToProps.

Related

setting state in axios.get(url).then() does not work when using react redux

While working with React and Redux I encountered this interesting observation.
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {fetchBooks} from '../actions'
class Sample extends Component {
componentDidMount() {
/* Fetching from server */
}
render(){
return(
{this.props.books.map(book => <Book key={book.title} {...book} />)}
)
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({fetchBooks}, dispatch);
}
const mapStateToProps = ({books}) => {
return {books};
}
connect(mapStateToProps, mapDispatchToProps)(Sample)
When I implement componentDidMount() function with redux as
...
componentDidMount() {
this.props.fetchBooks();
}
...
the state is updated and the render function is invoked.
However, when I use axios with promise, it doesn't work:
import axios from 'axios';
...
componentDidMount() {
const self = this;
axios.get(__URL__)
.then((response) => {
self.setState({books: response.data});
});
}
...
Does this mean you cannot mixin the two ways to set state when you use redux?
Or why does one method work while the other doesn't work when redux is used?
Well, you miss mess with a component state and redux state. when you call dispatch function using redux:
componentDidMount() {
this.props.fetchBooks();
}
It dispatches the action function and redux state updated. The redux state catch from component props by passing the first argument at
connect(mapStateToProps, mapDispatchToProps)(Sample)
when you call setState after get axios response, it update your component state not redux state. so, in that case yon may find your data from this.state.books not this.props.books. If you need to dispatch action function when axios get response.
componentDidMount() {
const self = this;
axios.get(__URL__)
.then((response) => {
//self.setState({books: response.data});
self.props.yourDispatchFunctionWithPassingTheReponseData(response.data);
});
}
more information about dispatch, please check out the link

I am not able to use mapDispatchToProps in my React + Redux application

In my React + Redux application I am trying to use mapDispatchToProps utility, But whenever I put this inside connect(mapStateToProps, mapDispatchToProps) it gives me an error saying Uncaught TypeError: dispatch is not a function at new ReduxApp (ReduxApp.js:42)
What could be the issue in this?
PS: below is the file
ReduxApp.js
import React from 'react';
import { Router, Route } from 'react-router-dom';
import { connect } from 'react-redux';
import { history } from './_helpers';
import { alertActions } from './_actions'
class ReduxApp extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
const { dispatch } = this.props;
dispatch(alertActions.success("hello world"));
}
handleChange(){
this.props.dispatch(alertActions.clear());
}
render(){
const { alert } = this.props;
return(
<div>
<h1>{alert.message}</h1>
<button onClick={this.handleChange}>clear</button> {/* this is working since this function is declared outside the mapDispatchToProps. */}
<button onClick={this.props.handleClick}>clear</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
alert : state.alert
});
const mapDispatchToProps = (dispatch) => ({
handleClick: () => dispatch(alertActions.clear())
});
const connectedApp = connect(mapStateToProps, mapDispatchToProps)(ReduxApp); // when I add mapDispatchToProps in the connect(), I get thhe issue.
export { connectedApp as ReduxApp }
you first need to pass dispatch as it is not available when using mapDispatchToProps (see this answer by #gaeron Redux's creator: https://github.com/reduxjs/react-redux/issues/255)
const mapDispatchToProps = dispatch => ({
handleClick: () => alertActions.clear(dispatch),
dispatch,
});
Update your actionCreator to dispatch the action now that dispatch's reference is available:
alert.clear = dispatch => {
// your logic
dispatch(ALERT_CLEAR_ACTION) // or whatever you named your action
}
And in your component:
handleChange = () => this.props.handleClick();
From React Redux Official Documentation
Why don't I have this.props.dispatch available in my connected component?
The connect() function takes two primary arguments, both optional. The first, mapStateToProps, is a function you provide to pull data from the store when it changes, and pass those values as props to your component. The second, mapDispatchToProps, is a function you provide to make use of the store's dispatch function, usually by creating pre-bound versions of action creators that will automatically dispatch their actions as soon as they are called.
If you do not provide your own mapDispatchToProps function when calling connect(), React Redux will provide a default version, which simply returns the dispatch function as a prop. That means that if you do provide your own function, dispatch is not automatically provided. If you still want it available as a prop, you need to explicitly return it yourself in your mapDispatchToProps implementation.
The issue got solved after returning dispatch in the mapDispatchToProps implementation
const mapDispatchToProps = (dispatch) => ({
handleClick: () => dispatch(alertActions.clear()),
dispatch, //returning dispatch solves the issue
});
Note: If we use PropTypes no need to retun mapDispatchToProps

bindActionCreators called on a dispatch

I was under the impression that the purpose of bindActionCreators was to wrap actionCreators in a dispatch function, and give these new functions a name (which could be passed to components as props, via mapDispatchToProps and connect).
However, a tutorial I found seemed to call bindActionCreators on a dispatch function (updatePerson), which seems to violate the whole point of bindActionCreators.
actions/update_person.js
import { UPDATE_PERSON } from './types';
export default function updatePerson(person) {
return dispatch => {
dispatch(updatePersonAsync(person));
}
}
function updatePersonAsync(person){
return {
type: UPDATE_PERSON,
payload: person
};
}
components/WantedCard.js
//connects redux actions to props
function mapDispatchToProps(dispatch) {
return bindActionCreators({
updatePerson: updatePerson,
deletePerson: deletePerson
}, dispatch);
}
What exactly am I getting wrong here, with my understanding? UpdatePerson is already bound(?)
This is the tutorial repo: https://github.com/lorenseanstewart/redux-wanted-list and blog post https://lorenstewart.me/2016/11/27/a-practical-guide-to-redux/
UpdatePerson is already bound(?)
No it wasn't it's just a normal function that you import.
In order to make it play with the redux flow cycle you need to dispatch this function.
When you are not passing mapDispatchToProps you get the dispatch function as a prop to your connected component, so to use it you would have to do it like this:
this.props.dispatch(updatePerson())
If you do decide to pass mapDispatchToProps to connect then you will not receive dispatch as a prop but you could wrap your actions with it:
const mapDispatchToProps = dispatch => {
return {
updatePerson: () => {
dispatch(updatePerson())
}
}
}
Or you can just pass an object:
const mapDispatchToProps = {
updatePerson,
deletePerson
}
Another way is to use bindActionCreators (like you mentioned in your post)
With this approach you can dispatch the action with this line of code:
function mapDispatchToProps(dispatch) {
return bindActionCreators({
updatePerson: updatePerson,
deletePerson: deletePerson
}, dispatch);
}
And call it like this:
this.props.updatePerson()
Note that you can use the Shorthand property names of ES2015 if the key matches the variable
function mapDispatchToProps(dispatch) {
return bindActionCreators({
updatePerson,
deletePerson
}, dispatch);
}
Another nice approach with bindActionCreators is to import all actions as alias (even different actions from different files):
import * as userActions from '../url';
import * as otherActions from '../otherUrl';
And then stack them all in one object (or separate them if you want):
function mapDispatchToProps(dispatch) {
const combinedActions = { ...userActions, ...otherActions };
return {
actions: bindActionCreators(combinedActions, dispatch)
};
}
Now you can refer any action via the actions object:
this.props.actions.myAction();
this.props.actions.myOtherAction();
You can read me about the various options in the docs

React redux passing event handler through connect & mapDispatchToProps vs. rendering child with props

Going through the react-redux docs, I'm trying to understand why the
todo example uses connect and mapDispatchToProps vs why the reddit example uses a more traditional render method & passing the dispatch through a handler as props to the child component. Is there a reason for this? I can only guess that it's because the former example has a container component correspond to only one presentational component whereas the latter example's container component contains two presentational components so it would not make sense to use connect (nor is it possible) on two components.
todo example :
const getVisibleTodos = (todos, filter) => {
...
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
reddit example:
class App extends Component {
...
handleChange(nextReddit) {
this.props.dispatch(selectReddit(nextReddit))
}
...
render() {
...
return (
<div>
<Picker value={selectedReddit}
onChange={this.handleChange}
options={[ 'reactjs', 'frontend' ]} />
<p>
...
It's perfectly okay to pass dispatch to your component unless you don't want your component to misuse the dispatch function and dispatch actions that are not supposed to be dispatched from that component!
If you want to limit your component, you don't want to pass dispatch directly to the component. You'll want to pass specific action creators through mapDispatchToProps.
I think it boils down to coding standards, really. If you decide to be strict on your components and not allow them to directly dispatch any action, you can use mapDispatchToProps to pass only specific action creators.
Bonus: In the first example, you're passing (id) => dispatch(toggleTodo(id)) function to your component. Try using bindActionCreators from redux instead of manually creating that function! Good luck.
UPDATE
export const dataLoadRequest = () => {
return {
type: 'DATA_LOAD_REQUEST',
}
}
In your Component.js file, you need to import two things.
import { dataLoadRequest } from 'actions.js';
import { bindActionCreators } from 'redux';
class Component extends React.Component{
...
componentDidMount(){
this.props.actions.dataLoadRequest();
}
...
}
const mapStateToProps = (state) => ({
...
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(dataLoadRequest, dispatch)
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(Component);

'dispatch' is not a function when argument to mapToDispatchToProps() in Redux

I am building an small application with redux, react-redux, & react. For some reason when using mapDispatchToProps function in tandem with connect (react-redux binding) I receive a TypeError indicating that dispatch is not a function when I try to execute the resulting prop. When I call dispatch as a prop however (see the setAddr function in the provided code) it works.
I'm curious as to why this is, in the example TODO app in the redux docs the mapDispatchToProps method is setup the same way. When I console.log(dispatch) inside the function it says dispatch is type object. I could continue to use dispatch this way but I would feel better knowing why this is happening before I continue any further with redux. I am using webpack with babel-loaders to compile.
My Code:
import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import { setAddresses } from '../actions.js';
import GeoCode from './geoCode.js';
import FlatButton from 'material-ui/lib/flat-button';
const Start = React.createClass({
propTypes: {
onSubmit: PropTypes.func.isRequired
},
setAddr: function(){
this.props.dispatch(
setAddresses({
pickup: this.refs.pickup.state.address,
dropoff: this.refs.dropoff.state.address
})
)
},
render: function() {
return (
<div>
<div className="row">
<div className="col-xs-6">
<GeoCode ref='pickup' />
</div>
<div className="col-xs-6">
<GeoCode ref='dropoff' />
</div>
</div>
<div className="row">
<div className="col-xs-6">
<FlatButton
label='Does Not Work'
onClick={this.props.onSubmit({
pickup: this.refs.pickup.state.address,
dropoff: this.refs.dropoff.state.address
})}
/>
</div>
<div className="col-xs-6">
<FlatButton
label='Works'
onClick={this.setAddr}
/>
</div>
</div>
</div>
);
}
})
const mapDispatchToProps = (dispatch) => {
return {
onSubmit: (data) => {
dispatch(setAddresses(data))
}
}
}
const StartContainer = connect(mapDispatchToProps)(Start)
export default StartContainer
If you want to use mapDispatchToProps without a mapStateToProps just use null for the first argument.
export default connect(null, mapDispatchToProps)(Start)
You are just missing the first argument to connect, which is the mapStateToProps method. Excerpt from the Redux todo app:
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Use
const StartContainer = connect(null, mapDispatchToProps)(Start)
instead of
const StartContainer = connect(mapDispatchToProps)(Start)
I solved it by interchanging the arguments, I was using
export default connect(mapDispatchToProps, mapStateToProps)(Checkbox)
which is wrong. The mapStateToProps has to be the first argument:
export default connect(mapStateToProps, mapDispatchToProps)(Checkbox)
It sounds obvious now, but might help someone.
I needed an example using React.Component so I am posting it:
import React from 'react';
import * as Redux from 'react-redux';
class NavigationHeader extends React.Component {
}
const mapStateToProps = function (store) {
console.log(`mapStateToProps ${store}`);
return {
navigation: store.navigation
};
};
export default Redux.connect(mapStateToProps)(NavigationHeader);
Issue
Here are a couple of things to notice in order to understand the connected component's behavior in your code:
The Arity of connect Matters: connect(mapStateToProps, mapDispatchToProps)
React-Redux calls connect with the first argument mapStateToProps, and second argument mapDispatchToProps.
Therefore, although you've passed in your mapDispatchToProps, React-Redux in fact treats that as mapState because it is the first argument. You still get the injected onSubmit function in your component because the return of mapState is merged into your component's props. But that is not how mapDispatch is supposed to be injected.
You may use mapDispatch without defining mapState. Pass in null in place of mapState and your component will not subject to store changes.
Connected Component Receives dispatch by Default, When No mapDispatch Is Provided
Also, your component receives dispatch because it received null for its second position for mapDispatch. If you properly pass in mapDispatch, your component will not receive dispatch.
Common Practice
The above answers why the component behaved that way. Although, it is common practice that you simply pass in your action creator using mapStateToProps's object shorthand. And call that within your component's onSubmit That is:
import { setAddresses } from '../actions.js'
const Start = (props) => {
// ... omitted
return <div>
{/** omitted */}
<FlatButton
label='Does Not Work'
onClick={this.props.setAddresses({
pickup: this.refs.pickup.state.address,
dropoff: this.refs.dropoff.state.address
})}
/>
</div>
};
const mapStateToProps = { setAddresses };
export default connect(null, mapDispatchToProps)(Start)
A pitfall some might step into that is covered by this question but isn't addressed in the answers as it is slightly different in the code structure but returns the exact same error.
This error occurs when using bindActionCreators and not passing the dispatch function
Error Code
import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'
const mapStatToProps = (state) => {
const { someState } = state.someState
return {
someState
}
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
someAction
});
};
export default connect(mapStatToProps, mapDispatchToProps)(someComponent)
Fixed Code
import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'
const mapStatToProps = (state) => {
const { someState } = state.someState
return {
someState
}
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
someAction
}, dispatch);
};
export default connect(mapStatToProps, mapDispatchToProps)(someComponent)
The function dispatch was missing in the Error code
React-redux 'connect' function accepts two arguments first is mapStateToProps and second is mapDispatchToProps check below ex.
export default connect(mapStateToProps, mapDispatchToProps)(Index);
`
If we don't want retrieve state from redux then we set null instead of mapStateToProps.
export default connect(null, mapDispatchToProps)(Index);
You're missing in the last statement. As we don't have mapStateToProps, so the statement will be like below
const StartContainer = connect(null, mapDispatchToProps)(Start)
When you do not provide mapDispatchToProps as a second argument, like this:
export default connect(mapStateToProps)(Checkbox)
then you are automatically getting the dispatch to component's props, so you can just:
class SomeComp extends React.Component {
constructor(props, context) {
super(props, context);
}
componentDidMount() {
this.props.dispatch(ACTION GOES HERE);
}
....
without any mapDispatchToProps
i am using like this.. its easy to understand first argument is mapStateToProps and second argument is mapDispatchToProps in the end connect with function/class.
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
Sometime this error also occur when you change the order of Component Function while passing to connect.
Incorrect Order:
export default connect(mapDispatchToProps, mapStateToProps)(TodoList);
Correct Order:
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
I got this issue when i wrote :
export default connect (mapDispatchToProps,mapStateToProps)(SearchInsectsComponent);
instead of
export default connect (mapStateToProps,mapDispatchToProps)(SearchInsectsComponent);

Categories

Resources