usedToBeFat usedToBeFat - 2 months ago 6
Javascript Question

what's the best way to deal with undefined props in react.js?

Let's assume I have an action that gets dispatched on page load, like say, in the index.js file.

example

store.dispatch(loadData());


in my reducer I initialize state to to an object. Something like this

function myReducer(state = {}, action)


now I have some smart component that subscribes to my state and then passes it down to another component to display the data. Another important note for this scenario is the fact that the retrieval of the data is happening asynchronously.
Let's also assume that the key of this object is some array.
So the markup component would have something like this

{this.props.object.key.map(k => do something)}


Now since key is undefined I can't call map on it and I blow up. The way I have been dealing with this, is by using a simply if check. If key is defined then run .map otherwise return null. Then by the time my data gets back from the server, the render will be called again due to a change in state that this component subscribed to. At this point the key is defined and map can be called.

Another approach, Is to define what your state will look like in the reducer. In other words, if I know that my state will be an object with an array property on it, I might do something like this.

const initialState = {
key:[]
}

function myReducer(state = initialState, action)


Doing this will benefit in the fact that now I won't need my if check since key is never undefined.

My questions is; are any of these approaches better than the other? Or perhaps, is there another way entirely to deal with this?

Answer

Generally, the approach I like to take is to define default props on the component which have the semantic meaning of "empty." For example, in context of the issue you describe I would typically structure my component like this (ES6 classes style):

class MyComponent extends React.Component {
    static defaultProps = {
        object: {
            key: []
        }
    };

    ...

    method() {
        // this.props.object.key is an empty array, but is overriden
        // with a value later after completion of the reducer
        // (trigerred asynchronously)
        this.props.object.key.map(doSomething);
    }
}

This is relatively clean, prevents the code from throwing at run time, and forces you to create well-defined behaviors for semantically null, empty, or undefined input states.