简体   繁体   中英

TypeError: Cannot read property 'loading' of undefined

I am getting that error. And I honestly do not why.

I passing loading as a prop. Its in my Redux store.

The initial state of loading is false

When I submit, loading should change to true and you should see the errors (If the email is not legit for example)

signup.js

class signup extends Component {

    constructor() {
        super();
        this.state = {
            email: '',
            password: '',
            confirmPassword: '',
            handle: '',
            errors: {}
        };
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.UI.errors) {
            this.setState({ errors: nextProps.UI.errors });
        }
    }

    handleSubmit = (event) => {
        event.preventDefault();
        this.setState({
            loading: true
        })
        const newUserData = {
            email: this.state.email,
            password: this.state.password,
            confirmPassword: this.state.confirmPassword,
            handle: this.state.handle
        };

        this.props.signupUser(newUserData, this.props.history);
    }


    handleChange = (event) => {
        this.setState({
            [event.target.name]: event.target.value
        });
    }


    render() {


        const {
            classes,
            UI: { loading } // Thats my ERROR
        } = this.props;
        const { errors } = this.state;


        return (
            <Grid container className={classes.form}>
                <Grid item sm />
                <Grid item sm>
                    <Typography variant="h2" className={classes.pageTitle}>
                        Signup
          </Typography>
                    <form noValidate onSubmit={this.handleSubmit}>
                        <TextField
                            id="email"
                            name="email"
                            type="email"
                            label="Email"
                            className={classes.textField}
                            helperText={errors.email}
                            error={errors.email ? true : false}
                            value={this.state.email}
                            onChange={this.handleChange}
                            fullWidth
                        />
                      ....... // Not important
                     
                        {errors.general && (
                            <Typography variant="body2" className={classes.customError}>
                                {errors.general}
                            </Typography>
                        )}
                        <Button
                            type="submit"
                            variant="contained"
                            color="primary"
                            className={classes.button}
                            disabled={loading}

                        >
                            Sgnup
                            {loading && (
                                <CircularProgress size={30} className={classes.progress} />
                            )}
                        </Button>
                        <br />
                        <small>All ready have  an account ? login in <Link to="/login">here</Link></small>
                    </form>
                </Grid>
                <Grid item sm />
            </Grid>
        )
    }
}

signup.propTypes = {
    classes: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired,
    UI: PropTypes.object.isRequired,
    signupUser: PropTypes.func.isRequired
}

const mapStateToProps = (state) => ({
    user: state.user,
    UI: state.UI
})


export default connect(mapStateToProps, { signupUser })(withStyles(styles)(signup));

Ui Reducer.js The initial state of loading is false I passing it as a prop to signup.js (and login.js)

import {
    SET_ERRORS,
    CLEAR_ERRORS,
    LOADING_UI,
    STOP_LOADING_UI
} from '../types';

const initialState = {
    loading: false,
    errors: null
};

export default function (state = initialState, action) {
    switch (action.type) {
        case SET_ERRORS:
            return {
                ...state,
                loading: false,
                errors: action.payload
            };
        case CLEAR_ERRORS:
            return {
                ...state,
                loading: false,
                errors: null
            };
        case LOADING_UI:
            return {
                ...state,
                loading: true
            };

        default:
            return state;
    }
}

that is my store.js

import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'


import userReducer from './reducers/userReducer'

import uiReducer from './reducers/uiReducer'

const initialState = {};

const middleware = [thunk]

const reducers = combineReducers({
    user: userReducer,

    ui: uiReducer
})



const composeEnhancers =
    typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
        ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
        : compose;

const enhancer = composeEnhancers(applyMiddleware(...middleware));
const store = createStore(reducers, initialState, enhancer);

export default store

I would appreciate any help

You have a problem in the combineReducers or in the mapStateToProps. In the reducer it's ui with small letters, and in the mapStateToProps it's capital. Change to this and it should work

const mapStateToProps = (state) => ({
    user: state.user,
    UI: state.ui
})

First, I see two errors. One, I think you are trying to update a Redux state by using React state function and that's not how it works. If its a state living within a React Component, then React.setState should be the way to go. If you are using Redux, then I am assuming that the proper way of updating its via Redux actions/dispatch from the component itself. I hope this gives you a starting to debug it. And two, Redux store is not set properly or that object destructuring is not working as you expected.

Well, your problem at the moment is in the store.js . You define initialState = {} and pass it as an argument to createStore . This empty object is then actually used instead of the initialState defined in Reducer.js . This object is passed on as props to the signup class. Thus you cannot extract the UI.loading value, because there is not one.

import the initial state from Reducer.js and use it instead of the empty initialState when calling createStore .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM