React Component - Why can dispatch in AsyncApp Components - javascript

Refer to this example
https://redux.js.org/advanced/example-reddit-api
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
selectSubreddit,
fetchPostsIfNeeded,
invalidateSubreddit
} from '../actions'
import Picker from '../components/Picker'
import Posts from '../components/Posts'
class AsyncApp extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.handleRefreshClick = this.handleRefreshClick.bind(this)
}
componentDidMount() {
const { dispatch, selectedSubreddit } = this.props
dispatch(fetchPostsIfNeeded(selectedSubreddit))
}
componentDidUpdate(prevProps) {
if (this.props.selectedSubreddit !== prevProps.selectedSubreddit) {
const { dispatch, selectedSubreddit } = this.props
dispatch(fetchPostsIfNeeded(selectedSubreddit))
}
}
handleChange(nextSubreddit) {
this.props.dispatch(selectSubreddit(nextSubreddit))
this.props.dispatch(fetchPostsIfNeeded(nextSubreddit))
}
handleRefreshClick(e) {
e.preventDefault()
const { dispatch, selectedSubreddit } = this.props
dispatch(invalidateSubreddit(selectedSubreddit))
dispatch(fetchPostsIfNeeded(selectedSubreddit))
}
render() {
const { selectedSubreddit, posts, isFetching, lastUpdated } = this.props
return (
<div>
<Picker
value={selectedSubreddit}
onChange={this.handleChange}
options={['reactjs', 'frontend']}
/>
<p>
{lastUpdated && (
<span>
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.{' '}
</span>
)}
{!isFetching && (
<button onClick={this.handleRefreshClick}>Refresh</button>
)}
</p>
{isFetching && posts.length === 0 && <h2>Loading...</h2>}
{!isFetching && posts.length === 0 && <h2>Empty.</h2>}
{posts.length > 0 && (
<div style={{ opacity: isFetching ? 0.5 : 1 }}>
<Posts posts={posts} />
</div>
)}
</div>
)
}
}
AsyncApp.propTypes = {
selectedSubreddit: PropTypes.string.isRequired,
posts: PropTypes.array.isRequired,
isFetching: PropTypes.bool.isRequired,
lastUpdated: PropTypes.number,
dispatch: PropTypes.func.isRequired
}
function mapStateToProps(state) {
const { selectedSubreddit, postsBySubreddit } = state
const { isFetching, lastUpdated, items: posts } = postsBySubreddit[
selectedSubreddit
] || {
isFetching: true,
items: []
}
return {
selectedSubreddit,
posts,
isFetching,
lastUpdated
}
}
export default connect(mapStateToProps)(AsyncApp)
The function can trigger the actions like 'fetchPostsIfNeeded' with this.props.dispatch(fetchPostsIfNeeded(nextSubreddit)). However, it supposes relate to mapDispatchToProps. So may i know the scenario why the program run succeeds with no error

Welcome to SO.
Actually, connect() has provided the dispatch to your component already.(https://react-redux.js.org/api/connect#example-usage)
You can take mapDispatchToProps as a middleware for creating methods with dispatch.
Lets say we have a store with state counter.
{
counter: 0
}
in mapDispatchToProps, we can create methods using in this component :
{
increment: ()=>{dispatch({ type: 'EDIT', payload: 1 })},
decrement: ()=>{dispatch({ type: 'EDIT', payload: -1 })}
}

Related

How can I use the context in the constructor in my React Form?

I have an issue in my React form. I must use the context to know what the name of the form is to set/get the value from the Redux store.
However, I have an issue. My form is in two parts. I set the values in the Redux store and if I need to go back to the previous part of the form, I still have the value saved. However, I have a little problem. I can't set the default state of the form input using the context since I don't know how to access the context in the constructor.
Could you help me achieve this?
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import { handleChange } from 'redux/actions';
import { connect } from 'react-redux';
import FormContext from 'context/FormContext';
export class TextInput extends Component {
constructor (props, context) {
super(props, context);
this.state = { value: this.getValue(context) || '' };
this.handleChange = this.handleChange.bind(this);
this.handleBlur = this.handleBlur.bind(this);
}
getRequired () {
if (this.props.required === true) {
return <span className="tw-font-semibold tw-text-red-500 tw-text-sm tw-ml-2">{this.props.t('required')}</span>;
}
}
handleChange (e) {
var value = e.target.value;
this.setState({ value: value });
}
handleBlur (context) {
this.props.handleChange(this.props.name, this.state.value, context.name);
}
getValue (context) {
if (this.props.input && this.props.input[context.name] && this.props.input[context.name][this.props.name]) {
return this.props.input[context.name][this.props.name];
} else {
return undefined;
}
}
render () {
return (
<FormContext.Consumer>
{context =>
<div className={`tw-flex tw-flex-col ${this.props.size} tw-px-2 tw-mb-3`}>
<label htmlFor={this.props.name} className="tw-text-sm tw-font-bold">{this.props.title || this.props.t('common:' + this.props.name)}{this.getRequired()}</label>
<input
value={this.state.value}
onChange={this.handleChange}
onBlur={() => {
this.handleBlur(context);
}}
type={this.props.type} id={this.props.name} placeholder={this.props.title} className="focus:tw-outline-none focus:tw-shadow-outline tw-bg-gray-300 tw-rounded-lg tw-py-2 tw-px-3" />
{this.props.errors && this.props.errors[context.name] && this.props.errors[context.name][this.props.name] && (
<div className="tw-bg-red-100 tw-mt-2 tw-border-l-4 tw-border-red-500 tw-text-red-700 tw-p-2 tw-text-sm">
<p>{this.props.errors[context.name][this.props.name]}</p>
</div>
)}
</div>
}
</FormContext.Consumer>
);
}
}
TextInput.defaultProps = {
size: 'w-full',
required: true,
type: 'text'
};
TextInput.propTypes = {
name: PropTypes.string.isRequired,
title: PropTypes.string,
size: PropTypes.string.isRequired,
required: PropTypes.bool,
type: PropTypes.string,
t: PropTypes.func.isRequired
};
const mapStateToProps = ({ errors, input }, ownProps) => {
return {
errors: errors,
input: input
};
};
export default connect(mapStateToProps, { handleChange })(withTranslation(['input'])(TextInput));
How about you wrap your FormContext wherever you call your TextInput. In that way, you could access your FormContext in your constructor.
function FormThatUsesTextInput() {
return (
<FormContext.Consumer>
{context => <TextInput context={context} {...otherProps} />}
</FormContext.Consumer>
)
}

React: How to update one component, when something happens on another component

I have an application with a table, the table has a checkbox to set a Tenant as Active, this variable is a global variable that affects what the user does in other screens of the application.
On the top right of the application, I have another component called ActiveTenant, which basically shows in which tenant the user is working at the moment.
The code of the table component is like this:
import React, { Component } from 'react';
import { Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
class ListTenants extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.id,
TestSiteCollectionUrl: row.TestSiteCollectionUrl,
TenantName: row.TenantName,
Email: row.Email
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
const columns = [
{
title: 'TenantName',
dataIndex: 'TenantName',
key: 'TenantName',
},
{
title: 'TestSiteCollectionUrl',
dataIndex: 'TestSiteCollectionUrl',
key: 'TestSiteCollectionUrl',
},
{
title: 'Email',
dataIndex: 'Email',
key: 'Email',
}
];
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
if(selectedRows[0].TenantName != undefined){
console.log(selectedRows[0].TenantName);
const options = {
method: 'post'
};
adalApiFetch(fetch, "/Tenant/SetTenantActive?TenantName="+selectedRows[0].TenantName.toString(), options)
.then(response =>{
if(response.status === 200){
Notification(
'success',
'Tenant set to active',
''
);
}else{
throw "error";
}
})
.catch(error => {
Notification(
'error',
'Tenant not activated',
error
);
console.error(error);
});
}
},
getCheckboxProps: record => ({
type: Radio
}),
};
return (
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
);
}
}
export default ListTenants;
And the code of the ActiveTenant component its also very simple
import React, { Component } from 'react';
import authAction from '../../redux/auth/actions';
import { adalApiFetch } from '../../adalConfig';
class ActiveTenant extends Component {
constructor(props) {
super(props);
this.state = {
tenant: ''
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant/GetActiveTenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
this.setState({ tenant: responseJson.TenantName });
}
})
.catch(error => {
this.setState({ tenant: '' });
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
return (
<div>You are using tenant: {this.state.tenant }</div>
);
}
}
export default ActiveTenant;
The problem is, if I have multiple tenants on my database registered and I set them to active, the server side action occurs, and the state is changed, however on the top right its still showing the old tenant as active, UNTIL I press F5 to refresh the browser.
How can I achieve this?
For the sake of complete understandment of my code I will need to paste below other components:
TopBar which contains the active tenant
import React, { Component } from "react";
import { connect } from "react-redux";import { Layout } from "antd";
import appActions from "../../redux/app/actions";
import TopbarUser from "./topbarUser";
import TopbarWrapper from "./topbar.style";
import ActiveTenant from "./activetenant";
import TopbarNotification from './topbarNotification';
const { Header } = Layout;
const { toggleCollapsed } = appActions;
class Topbar extends Component {
render() {
const { toggleCollapsed, url, customizedTheme, locale } = this.props;
const collapsed = this.props.collapsed && !this.props.openDrawer;
const styling = {
background: customizedTheme.backgroundColor,
position: 'fixed',
width: '100%',
height: 70
};
return (
<TopbarWrapper>
<Header
style={styling}
className={
collapsed ? "isomorphicTopbar collapsed" : "isomorphicTopbar"
}
>
<div className="isoLeft">
<button
className={
collapsed ? "triggerBtn menuCollapsed" : "triggerBtn menuOpen"
}
style={{ color: customizedTheme.textColor }}
onClick={toggleCollapsed}
/>
</div>
<ul className="isoRight">
<li
onClick={() => this.setState({ selectedItem: 'notification' })}
className="isoNotify"
>
<TopbarNotification locale={locale} />
</li>
<li>
<ActiveTenant />
</li>
<li
onClick={() => this.setState({ selectedItem: "user" })}
className="isoUser"
>
<TopbarUser />
<div>{ process.env.uiversion}</div>
</li>
</ul>
</Header>
</TopbarWrapper>
);
}
}
export default connect(
state => ({
...state.App.toJS(),
locale: state.LanguageSwitcher.toJS().language.locale,
customizedTheme: state.ThemeSwitcher.toJS().topbarTheme
}),
{ toggleCollapsed }
)(Topbar);
App.js which contains the top bar
import React, { Component } from "react";
import { connect } from "react-redux";
import { Layout, LocaleProvider } from "antd";
import { IntlProvider } from "react-intl";
import { Debounce } from "react-throttle";
import WindowResizeListener from "react-window-size-listener";
import { ThemeProvider } from "styled-components";
import authAction from "../../redux/auth/actions";
import appActions from "../../redux/app/actions";
import Sidebar from "../Sidebar/Sidebar";
import Topbar from "../Topbar/Topbar";
import AppRouter from "./AppRouter";
import { siteConfig } from "../../settings";
import themes from "../../settings/themes";
import { themeConfig } from "../../settings";
import AppHolder from "./commonStyle";
import "./global.css";
import { AppLocale } from "../../dashApp";
import ThemeSwitcher from "../../containers/ThemeSwitcher";
const { Content, Footer } = Layout;
const { logout } = authAction;
const { toggleAll } = appActions;
export class App extends Component {
render() {
const { url } = this.props.match;
const { locale, selectedTheme, height } = this.props;
const currentAppLocale = AppLocale[locale];
return (
<LocaleProvider locale={currentAppLocale.antd}>
<IntlProvider
locale={currentAppLocale.locale}
messages={currentAppLocale.messages}
>
<ThemeProvider theme={themes[themeConfig.theme]}>
<AppHolder>
<Layout style={{ height: "100vh" }}>
<Debounce time="1000" handler="onResize">
<WindowResizeListener
onResize={windowSize =>
this.props.toggleAll(
windowSize.windowWidth,
windowSize.windowHeight
)
}
/>
</Debounce>
<Topbar url={url} />
<Layout style={{ flexDirection: "row", overflowX: "hidden" }}>
<Sidebar url={url} />
<Layout
className="isoContentMainLayout"
style={{
height: height
}}
>
<Content
className="isomorphicContent"
style={{
padding: "70px 0 0",
flexShrink: "0",
background: "#f1f3f6",
position: "relative"
}}
>
<AppRouter url={url} />
</Content>
<Footer
style={{
background: "#ffffff",
textAlign: "center",
borderTop: "1px solid #ededed"
}}
>
{siteConfig.footerText}
</Footer>
</Layout>
</Layout>
<ThemeSwitcher />
</Layout>
</AppHolder>
</ThemeProvider>
</IntlProvider>
</LocaleProvider>
);
}
}
export default connect(
state => ({
auth: state.Auth,
locale: state.LanguageSwitcher.toJS().language.locale,
selectedTheme: state.ThemeSwitcher.toJS().changeThemes.themeName,
height: state.App.toJS().height
}),
{ logout, toggleAll }
)(App);
I think this should be enough to illustrate my question.
You're not using redux correctly there. You need to keep somewhere in your redux state your active tenant; That information will be your single source of truth and will be shared among your components throughout the app. Every component that will need that information will be connected to that part of the state and won't need to hold an internal state for that information.
Actions, are where you would call your API to get your active tenant information or set a new tenant as active. These actions wil call reducers that will change your redux state (That includes your active tenant information) and those redux state changes will update your app components.
You should probably take some time to read or re-read the redux doc, it's short and well explained !

this.props.dispatch is not a function in react with redux

I am calling api with redux action, so i created the reducers, action and store. But when i calling the redux action from the view part. I am getting the following error.
this.props.dispatch is not a function
Below is my reducer, actions and view part(React) Code which can help you to understand the code.
Note: when i console.log(this.props), I am not getting dispatch() function.
actions.js
import {
FETCH_WORKS_SUCCESS,
FETCH_WORKS_FAILURE
} from './actionTypes'
export function fetchFeaturedWork(){
return dispatch => {
return fetch("https://api.com/api/wp-json/customapi/all_posts?category=work&featured=true")
.then(res => res.json())
.then(json => {
dispatch(fetchFeaturedWorkSuccess(json.works));
return json.works;
})
};
}
export const fetchFeaturedWorkSuccess = works => ({
type: FETCH_WORKS_SUCCESS,
payload: { works }
});
reducer.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
FETCH_WORKS_SUCCESS,
FETCH_WORKS_FAILURE
} from '../actions/actionTypes'
const initialState = {
isMenuOpen: null,
isMobile: false,
error:null,
works:[]
}
const reducer = (state = initialState, action) => {
switch (action.type) {
case OPEN_MENU:
return {...state, isMenuOpen: true}
case CLOSE_MENU:
return {...state, isMenuOpen: false}
case SET_DEVICE_TYPE:
return {...state, isMobile: action.isMobile}
case FETCH_WORKS_SUCCESS:
return {...state,works:action.payload.works}
case FETCH_WORKS_FAILURE:
return {...state,error:action.payload.error,works:[]}
default:
return state
}
}
export default reducer;
store.js
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers/reducer';
import thunk from "redux-thunk";
let store = createStore(rootReducer,applyMiddleware(thunk))
export default store
App.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import Slider from "react-slick";
import Footer from '../footer'
import './index.css';
import { connect } from 'react-redux'
import { openMenu,fetchFeaturedWork } from '../../actions/actionCreators'
import Header from '../header'
import arrowRight from '../../images/arrow-right.svg'
import arrowLeft from '../../images/arrow-left.svg'
const mapStateToProps = (state) => ({
isMobile: state && state.isMobile
})
const mapDispatchToProps = (dispatch, ownProps) => ({
openMenu: (isMobile) => dispatch(openMenu(ownProps.isMobile))
})
class Work extends Component {
getImgSlider = (slider) => {
this.imgSlider = slider
}
getTextSlider = (slider) => {
this.textSlider = slider
}
componentDidMount(){
this.props.dispatch(fetchFeaturedWork());
}
render() {
let className = 'idz_work'
if (this.props.isMobile) {
className = 'idle'
}
return (
<div>
{
this.props.isMobile ?
null
:
<Link to='/home'>
<div className='idz_sidebar' style={{ left: 0 }}>
<div>
<label>FEATURED</label>
</div>
</div>
</Link>
}
<div className={className}>
{!this.props.isMobile &&
<Header logo="dark"/>
}
<div className="content">
<label className="light-gray" style={this.props.isMobile ? { fontSize: '1.3rem' } : { fontSize: '2rem' }}>Featured Works</label>
<hr style={this.props.isMobile ? { marginBottom: '0.5rem', marginTop: '0.5rem' } : {}} />
<hr style={this.props.isMobile ? { marginBottom: '0.5rem', marginTop: '0.5rem' } : {}} />
<label className="light-gray" style={this.props.isMobile ? { fontSize: '1.3rem' } : { fontSize: '2rem' }}>All Works</label>
<hr style={this.props.isMobile ? { marginBottom: '0.5rem', marginTop: '0.5rem' } : {}} />
<hr />
</div>
{this.props.isMobile ? null : <Footer />}
</div>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Work);
When you use mapDispatchToProps, dispatch is not longer available in props. So, either get rid of mapDispatchToProps and use this.props.dispatch. Or move all dispatch functions to mapDispatchToProps.

React Native: Component rerender but props has not changed

I'm encountering this strange issue that I can figure out why is happing.
This should not be happening since the prop passed down to the History component has not been updated.
./components/History.js
...
const History = ({ previousLevels }) => {
return (
<ScrollView style={styles.container}>
{previousLevels.reverse().map(({ date, stressValue, tirednessValue }) => {
return (
<CardKBT
key={date}
date={date}
stressValue={stressValue}
tirednessValue={tirednessValue}
/>
)
})}
</ScrollView>
)
}
...
export default History
As can be seen in this code (below), the prop to the History is only updated once the user press Save.
App.js
import React from 'react'
import { View, ScrollView, StyleSheet } from 'react-native'
import { AppLoading, Font } from 'expo'
import Store from 'react-native-simple-store'
import { debounce } from 'lodash'
import CurrentLevels from './components/CurrentLevels'
import History from './components/History'
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
isLoadingComplete: false,
currentLevels: {
stressValue: 1,
tirednessValue: 1,
},
previousLevels: [],
}
this.debounceUpdateStressValue = debounce(this.onChangeStressValue, 50)
this.debounceUpdateTirednessValue = debounce(
this.onChangeTirednessValue,
50
)
}
async componentDidMount() {
const previousLevels = await Store.get('previousLevels')
if (previousLevels) {
this.setState({ previousLevels })
}
}
render() {
const { stressValue, tirednessValue } = this.state.currentLevels
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
...
/>
)
} else {
return (
<View style={{ flex: 1 }}>
<CurrentLevels
stressValue={stressValue}
onChangeStressValue={this.debounceUpdateStressValue}
tirednessValue={tirednessValue}
onChangeTirednessValue={this.debounceUpdateTirednessValue}
onSave={this.onSave}
/>
<History previousLevels={this.state.previousLevels} />
</View>
)
}
}
...
onChangeStressValue = stressValue => {
const { tirednessValue } = this.state.currentLevels
this.setState({ currentLevels: { stressValue, tirednessValue } })
}
onChangeTirednessValue = tirednessValue => {
const { stressValue } = this.state.currentLevels
this.setState({ currentLevels: { stressValue, tirednessValue } })
}
onSave = () => {
Store.push('previousLevels', {
date: `${new Date()}`,
...this.state.currentLevels,
}).then(() => {
Store.get('previousLevels').then(previousLevels => {
this.setState({
currentLevels: { stressValue: 1, tirednessValue: 1 },
previousLevels,
})
})
})
}
}
The component will re-render when one of the props or state changes, try using PureComponent or implement shouldComponentUpdate() and handle decide when to re-render.
Keep in mind, PureComponent does shallow object comparison, which means, if your props have nested object structure. It won't work as expected. So your component will re-render if the nested property changes.
In that case, you can have a normal Component and implement the shouldComponentUpdate() where you can tell React to re-render based on comparing the nested properties changes.

Dispatching an in-progress action in Redux

I have a signup form, which posts data asynchronously to an API and then does some stuff based on the response. I am dispatching a "signup_in_progress" action as soon as the function is called, with a payload of "true", and update my state based on that, then dispatching this action with a payload of "false" when the promise is resolved.
I can see that the dispatch happens as intended by putting a console.log() statement in the reducer.
What I would like to happen is for a spinner to appear instead of the signup form when the signup_in_progress piece of state is "true." But that's not happening. Any idea what I'm missing?
My action:
export function signUpUser(props) {
return function(dispatch) {
dispatch({ type: SIGNUP_IN_PROGRESS, payload: true });
axios
.post(`${ROOT_URL}/signup`, props)
.then(() => {
dispatch({ type: SIGNUP_IN_PROGRESS, payload: false });
dispatch({ type: SIGNUP_SUCCESS });
browserHistory.push(`/signup/verify-email?email=${props.email}`);
})
.catch(response => {
dispatch({ type: SIGNUP_IN_PROGRESS, payload: false });
dispatch(authError(SIGNUP_FAILURE, response.response.data.error));
});
};
}
The relevant part of my reducer:
import {
...
SIGNUP_IN_PROGRESS,
SIGNUP_SUCCESS,
SIGNUP_FAILURE...
} from '../actions/types';
export default function(state = {}, action) {
switch (action.type) {
...
case SIGNUP_IN_PROGRESS:
return { ...state, signing_up: action.payload };
...
My connected component:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import * as actions from '../../actions';
import SignupFirstPage from './signupComponents/signupFirstPage';
import SignupSecondPage from './signupComponents/signupSecondPage';
import SignupThirdPage from './signupComponents/SignupThirdPage';
import Spinner from 'react-spinkit';
class SignUp extends Component {
constructor(props) {
super(props);
this.nextPage = this.nextPage.bind(this);
this.previousPage = this.previousPage.bind(this);
this.state = {
page: 1
};
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
nextPage() {
this.setState({ page: this.state.page + 1 });
}
previousPage() {
this.setState({ page: this.state.page - 1 });
}
handleFormSubmit(props) {
this.props.signUpUser(props);
}
render() {
const { handleSubmit } = this.props;
const { page } = this.state;
if (this.props.signingUp) {
return (
<div className="dashboard loading">
<Spinner name="chasing-dots" />
</div>
);
}
return (
<div>
{page === 1 && <SignupFirstPage onSubmit={this.nextPage} />}
{page === 2 && (
<SignupSecondPage
previousPage={this.previousPage}
onSubmit={this.nextPage}
/>
)}
{page === 3 && (
<SignupThirdPage
previousPage={this.previousPage}
onSubmit={values => this.props.signUpUser(values)}
/>
)}
<div>
{this.props.errorMessage &&
this.props.errorMessage.signup && (
<div className="error-container">
Oops! {this.props.errorMessage.signup}
</div>
)}
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
singingUp: state.auth.signing_up,
errorMessage: state.auth.error
};
}
SignUp = reduxForm({ form: 'wizard' })(SignUp);
export default connect(mapStateToProps, actions)(SignUp);
You just have a typo in your code:
function mapStateToProps(state) {
return {
singingUp: state.auth.signing_up, // TYPO!!
errorMessage: state.auth.error
};
}
should be changed to
function mapStateToProps(state) {
return {
signingUp: state.auth.signing_up,
errorMessage: state.auth.error
};
}
I recommend using redux-pack which allows you to handle three phases of the request in the reducer: start, success and error.
Then you can use the start handler to set the boolean to true, and on success set it to false.

Categories

Resources