Search code examples
reactjsreact-reduxaxiosreact-proptypes

PropType.shape({}) Failure Warning: Invalid Type


I'm trying to set up the PropType of a prop from a Redux-State which is an object that looks like this:

sDate = {
        all_day: true,                               //bool
        category: "sCategory",                       //string
        created_at: "2021-07-31T10:06:02.545637Z",   //string
        description: "sDescribtion",                 //string
        end: Sat Jul 31 2021 14:05:00 GMT+0200       //Date
        id: 49,                                      //number
        start: Sat Jul 31 2021 16:05:00 GMT+0200     //Date
        title: "sTitle",                             //string
        type: "sType",                               //string
}

At least, this is what it looks like inside the axios.get request function right before dispatch. I can also read out the content of the object inside the Component. I'm using it in a function Component, as you will see below.

First, I tried to set it up as PropType.object.isRequired, but I got the warning

Warning: Failed prop type: Invalid prop `sDate` of type `array` supplied to `EditDate`, expected `object`.

Changeing to PropType.array.isRequired results in the warning

Warning: Failed prop type: Invalid prop `sDate` of type `object` supplied to `EditDate`, expected `array`.

That's when I decided to use PropTypes.shape({}).

Below, you can see the function component with the current PropTypes setup

function EditDate(props) {

    useEffect(() => {
        props.getSingleDate(id)
    },[])

    const { id } = useParams();

    return (
        <Fragment>
         ...
        </Fragment>
    );
}

EditDate.propTypes = {
    getSingleDate: PropTypes.func.isRequired,
    deleteDate: PropTypes.func.isRequired,
    sDate: PropTypes.shape({
        all_day: PropTypes.bool.isRequired,
        category: PropTypes.string.isRequired,
        created_at: PropTypes.string,
        description: PropTypes.string.isRequired,
        end: PropTypes.instanceOf(Date).isRequired,
        id: PropTypes.number.isRequired,
        start: PropTypes.instanceOf(Date).isRequired,
        title: PropTypes.string.isRequired,
        type: PropTypes.string.isRequired,
    }),
};

const mapStateToProps = state => ({
    sDate: state.dateReducer.dates
});

export default connect(
    mapStateToProps,
    { getSingleDate, deleteDate }
)(EditDate);


I still get the warning

Warning: Failed prop type: Invalid prop `sDate` of type `array` supplied to `EditDate`, expected `object`.

What am I doing wrong?

I also tried changing the Redux-Reducer, because it might be set up the wrong way:

const initialState = {
    dates: []               //  <-- does this determin what React expects?
};

export default function(state = initialState, action) {
    switch (action.type) {
        case GET_DATES:
            return {
                ...state,
                dates: action.payload
            };
        case GET_SINGLE_DATE:
            state.dates = Object    //  <-- this had no effect in the matter discussed
            return {
                state,
                dates: action.payload
            };
            ...

In the above example, in case GET_DATES I don't get any problem with the action.payload as props in the corresponding Component (there, PropTypes.array works).


EDIT:

this works:

sDate: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,

Can someone explain to me why? The docs are a little bit vague on it.


EDIT 2:

I had to correct a logical error in the Redux Reducer: GET_DATES and GET_SINGLE_DATE really shoud have their own representation in Redux-state:

const initialState = {
    dates: [],                
    sDate: []                
};
...
...
        case GET_SINGLE_DATE:
            return {
                state,
                sDate: action.payload
            };
            ...

EDIT 3:

As explained in the answer below, I had to change the initialSate of the Reducer, i.o. to make it work right:

const initialState = {
    dates: [],                
    sDate: {}      //now, the initial state is an object, too                
};

therefore, to make proper use of it:

EditDate.propTypes = {
...
  sDate: PropType.object.isRequired,
...
}

Solution

  • If I understood well, we have a date variable, which is an empty array as initial state. So, before the api call occur, the app will understand that this variable is an array. After the api call, we are receiving an object and replacing the array as data value. So we have a change of type here, which generate the warning.

    When you use

    sDate: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
    
    

    you are just saying you are okay with both types on this variable, which removes warning, but it's not ideal.

    To correctly resolve this issue, you just need to put an empty object as initial state, so this variable will be an object before and after the api call.