I have an api that give my react app data
{
"data_for_action1": ...
"data_for_action2": ...
"data_for_action3": ...
}
To propagate the data through redux I can
this.props.reduxAction1({
"data_for_action1": ....
})
this.props.reduxAction2({
"data_for_action2": ....
})
this.props.reduxAction3({
"data_for_action3": ....
})
export default connect(
mapStateToProps,
{ reduxAction1, reduxAction2, reduxAction3 }
)(MyComponent);
Call all redux action successively, but the problem is that I have to do this for all component that use this api.
Is there a way to split this in action function instead
export const myCombineReduxAction = myInfo => {
// call reduxAction1, reduxAction2, and reduxAction3
}
instead of
export const reduxAction1 = myInfo => ({
type: ActionType1,
payload: { myInfo }
});
export const reduxAction2 = myInfo => ({
type: ActionType2,
payload: { myInfo }
});
export const reduxAction3 = myInfo => ({
type: ActionType3,
payload: { myInfo }
});
I think so:-
You could create a custom function in your reducer:
given if all your action use the same dispatch from the same reducer
args or props passed to the custom function could be anything. But a make sure to pass the dispatch too
in reducer:-
export const myCombineReduxAction = (dispatch, myInfo) => {
// then run whatever dispatch here
dispatch({
type: ActionType1,
payload: { myInfo }
})
dispatch({
type: ActionType2,
payload: { myInfo }
})
dispatch({
type: ActionType2,
payload: { myInfo }
})
}
in demo component:-
import { useDispatch } from "react-redux";
import { myCombineReduxAction } from "../redux/reducer/whateverReducer";
const Demo = () => {
const dispatch = useDispatch();
const getData = () => {
const myInfo = 'something'
myCombineReduxAction(dispatch, myInfo)
}
return (<>Something</>)
}
If you use thunk you can do the following:
export const myCombineReduxAction = (myInfo) => (
dispatch
) => {
dispatch(reduxAction1(myInfo));
dispatch(reduxAction2(myInfo));
dispatch(reduxAction3(myInfo));
};
Related
I've been trying to dispatch a function that will call an async parse cloud function. It worked well in my other projects when i used them in functions. But this is the first time i'm using them in a component and when i call the dispatch from map dispatch to props, I get this error. Please help me out.
ProfileHeader.js
import React, { Component } from 'react';
import Cover_Image from './Cover_Image.jpg';
import Profile_Pic from './Profile_Pic.svg';
import './ProfileHeader.css';
import { connect } from 'react-redux';
import { fetchUserProfile } from '../../Redux/UserProfile-Redux/UserProfileActionMethods';
class ProfileHeader extends Component {
componentDidMount() {
this.props.fetchUserProfile()
}
render() {
return (
<div className="profile-header-layout"></div>
)
}
}
const mapStatetoProps = (state) => {
return {
profile: state.UserProfile
}
}
const mapDispatchtoProps = (dispatch) => {
return {
fetchUserProfile: () => { dispatch(fetchUserProfile()) }, dispatch,
}
}
export default connect(mapDispatchtoProps, mapStatetoProps)(ProfileHeader)
The action Method:
import Parse from 'parse/dist/parse.min.js';
import { FETCH_USERPROFILE_FAILURE, FETCH_USERPROFILE_REQUEST, FETCH_USERPROFILE_SUCCESS } from './UserProfileActions';
const params = { username: "prvnngrj" }
export const fetchUserProfileRequest = () => {
return {
type: FETCH_USERPROFILE_REQUEST
}
}
export const fetchUserProfileSuccess = (userprofiles) => {
return {
type: FETCH_USERPROFILE_SUCCESS,
payload: userprofiles
}
}
export const fetchUserProfileFailure = (error) => {
return {
type: FETCH_USERPROFILE_FAILURE,
payload: error
}
}
export const fetchUserProfile = () => {
return async dispatch => {
dispatch(fetchUserProfileRequest)
try {
const responsedata = await Parse.Cloud.run("GetUserProfileForUsername", params);
const userprofiles = responsedata;
dispatch(fetchUserProfileSuccess(userprofiles))
}
catch (error) {
const errorMessage = error.message
dispatch(fetchUserProfileFailure(errorMessage))
}
}
}
Please ignore parts of code which do not make it relevant, its straight from the project
You mixed up the order of your arguments, so this.props.dispatch is actually your state!
You need to change
export default connect(mapDispatchtoProps, mapStatetoProps)(ProfileHeader)
to:
export default connect(mapStatetoProps, mapDispatchtoProps)(ProfileHeader)
If you can switch to function components and the useSelector/useDispatch hooks you should. This is the current recommended approach and it's easier to use.
I have following Action:
import axios from 'axios';
export function getAPIData(id)
{
return (dispatch) =>
{
axios.get('http://localhost:5000/api/' + id)
.then(res =>
{
dispatch(
{
type: 'DONE',
payload: res.data
});
});
}
}
Then in my Component I`m dispatching the action:
componentDidMount()
{
this.props.dispatch(getAPIData());
}
And then:
function mapStateToProps(state)
{
console.log(state);
return {
data: state.result
};
}
export default connect(mapStateToProps)(Rows);
In console, when I try to find the payload, it says what is bellow.
function()
arguments: TypeError: 'arguments', 'callee', and 'caller' cannot be
accessed in this context.
caller: TypeError: 'arguments', 'callee', and 'caller' cannot be
accessed in this context.
length: 1
name: ""
Where is problem? Thanks a lot.
to dispatch an action you need to provide mapDispatchToProps .
First import your action
import { getAPIData } from "../store/actions/getAPIData";
then build mapDispatchToProps
const mapDispatchToProps = (dispatch) => {
return {
getAPIData: (props = null) => {
dispatch(getAPIData(props));
},
};
};
add this alongside mapStateToProps
export default connect(mapStateToProps , mapDispatchToProps)(Rows);
now you can call the action like this
componentDidMount()
{
this.props.getAPIData();
}
In this my action the user's log out of my application is exported in react
export const logoutUser = () => {
return dispatch => {
dispatch(
{
type: LOGOUT_USER
}
)
.then(() => {
logoutUserSuccess(dispatch, )
})
.catch((err) => {
logoutUserError(err, dispatch)
})
}
}
const logoutUserSuccess = (dispatch) => {
dispatch(
{
type: LOGOUT_USER_SUCCESS
}
)
AsyncStorage.removeItem('#token_jwt')
console.log('saiu')
Actions.loginScreen()
}
const logoutUserError = (err, dispatch) => {
dispatch(
{
type: LOGOUT_USER_ERROR
}
)
Alert.alert('Erro ao sair da conta')
console.log(err)
}
is my Reducer
case LOGOUT_USER:
return {
...state
}
case LOGOUT_USER_SUCCESS:
return {
INITIAL_STATE
}
case LOGOUT_USER_ERROR:
return {
...state
}
is my screen to logout
onLogout() {
this.props.logoutUser()
}
const mapStateToProps = state => (
{
email: state.Authentication.email
}
)
export default connect(mapStateToProps, { logoutUser })(Home)
The return is the following error
I put the email on the mapStateToProps, because I don't know how to leave it blank, what matters to me is the logout
You can try creating a mapDispatchToProps function and dispatch the action logoutUser from inside the function and pass it as a second argument to connect.
In doing so, you can invoke the LogoutUser from mapDispatchToProps in your onLogout function.
import {logoutUser} from './youractions.js'
onLogout() {
this.props.LogoutUser();
}
const mapDispatchToProps = (dispatch) => ({
LogoutUser: () => dispatch(logoutUser()),
});
export default connect(null, mapDispatchToProps)(Home);
I'm switching my state to redux and ran into this error
TypeError: sourceSelector is not a function
I've pasted the code from the component and the action i'm dispatching, i think its something in mapDispatchToProps but not sure
component
componentDidMount() {
const { dispatch } = this.props;
dispatch(getTableData(this.props.apiUrl, this.state.limit, this.state.skip));
}
const mapStateToProps = ({tableData}) => ({
tableData,
});
function mapDispatchToProps (dispatch) {
return {
getTableData: (data) => dispatch(getTableData(data)),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
{ getTableData }
)(SearchableTable);
action
import * as TYPES from './types';
import axios from 'axios';
export const getTableData = (url, limit, skip) => async dispatch => {
try {
dispatch({ type: TYPES.FETCH_TABLE_DATA_LOADING });
const response = await axios.post(url, {
limit: limit,
skip: skip,
});
await dispatch({
type: TYPES.FETCH_TABLE_DATA,
payload: response.data,
});
dispatch({ type: TYPES.FETCH_TABLE_DATA_FINISHED });
} catch (err) {
dispatch({ type: TYPES.INSERT_ERROR, payload: err.response });
}
};
Try this
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { getTableData } from "actions";
componentDidMount() {
// Make sure you use this.props.getTable data and not the raw imported
// getTableData function
this.props.getTableData(this.props.apiUrl, this.state.limit, this.state.skip));
}
const mapStateToProps = state => ({
tableData: state.tableData
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
getTableData
},
dispatch
);
return connect(
mapStateToProps,
mapDispatchToProps
)(SearchableTable);
Looking for guidance using redux-token-auth. Throwing this Type Error:
Error
All the creators' examples involve making the calls from the Component class like so:
// EXAMPLE: components/SignInScreen.jsx
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { signInUser } from '../redux-token-auth-config' // <-- note this is YOUR file, not the redux-token-auth NPM module
class SignInScreen extends Component {
constructor (props) { ... }
...
submitForm (e) {
e.preventDefault()
const { signInUser } = this.props
const {
email,
password,
} = this.state
signInUser({ email, password }) // <-<-<-<-<- here's the important part <-<-<-<-<-
.then(...)
.catch(...)
}
render () {
const { submitForm } = this
<div>
<form onSubmit={submitForm}>...</form>
</div>
}
}
export default connect(
null,
{ signInUser },
)(SignInScreen)
Is it feasible to move the calls up to an action file? In documentation, he mentions that
registerUser, signInUser, and signOutUser are Redux Thunk actions and
thus, when wired through mapDispatchToProps return Promises.
I'm digging through the source code, but I can't figure out what changes when the sign in dispatch is mapped via Redux rather than directly imported and called. If anyone is familiar with this extension, any ideas would be much appreciated!
This is my attempt that throws the error:
// /actions/auth.js
import { signInUser, signOutUser } from '../redux-token-auth-config'
export const Login = (email, password) => {
return (dispatch) => {
dispatch(LoginStart());
signInUser({ email, password })
.then((response) => dispatch(LoginSuccess(response.data.data)))
.catch((error) => dispatch(LoginError(error)));
};
};
export const LoginStart = () => ({
type: 'LOGIN::START'
});
export const LoginSuccess = (data) => ({
type: 'LOGIN::SUCCESS',
payload: data
});
export const LoginError = (error) => ({
type: 'LOGIN::ERROR',
payload: error
})
export const Logout = () => {
return (dispatch) => {
dispatch(SessionCleanup())
signOutUser()
.then((response) => console.log('Success'))
.catch((error) => console.log(error))
}
}
export const SessionCleanup = () => ({
type: 'LOGIN::SESSION_CLEANUP'
})
Assuming you are trying to call Login from a component I had the same issue and fixed it by doing the following:
export default connect(state => ({}), { signInUser })(FooBar);
When I called the action I passed along signInUser.
this.props.fooBarBaz(email, password, signInUser);
This allowed me to use signInUser outside of the component just as I did within it.
So in your case it should be as simple as keeping:
export default connect(
null,
{ signInUser },
)(SignInScreen)
and calling Login like:
Login(email, password, signInUser);