Reputation:
I have a firebase realtime database, a JSON based no sql database, I have 5 fields in that database, storing these:
field 1: STRING
field 2: STRING
field 3: STRING
field 4: STRING
field 5: ARRAY OF OBJECTS
so that database with real example looks something like this:
name: STRING
age: NUMBER
email: STRING
phoneNumber: STRING
skills: OBJECT[]
now I am downloading all these info from the firebase as a single variable(var
) called
snapshot.val()
. and then updating all the states using setState
at once like this:
this.setState({
state_name: snapshot.val().name,
state_age: snapshot.val().age,
state_email: snapshot.val().email,
state_phoneNumber: snapshot.val().phoneNumber,
state_skills: snapshot.val().skills
});
now this statement works fine if all the values are there in the database and it also works fine if the strings aren't there in the database but it runs into an error if the skills field is undefined
in the database.
So setState
doesn't throw an error when strings are undefined but it does throw error when arrays are undefined. it happened even with simple string array. Now if one field doesn't exist and an error is thrown, the entire setState
fails, so in summary, if multiples states are being updated at once and one of the state upadate fails with an exception or error, all the updates fail and I have been updating such delicate data with separate setState
statements with only one state being updated inside its own try catch block. So to update multiple states that have the potential to crash, I am using multiple try catch blocks. something like this:
try {
this.setState({
ownerNameValue: snapshot.val().owner_name,
});
} catch {}
try {
this.setState({
phoneNumberValue: snapshot.val().phone_number,
});
} catch {}
try {
this.setState({
specialityValue: snapshot.val().specialty,
});
} catch {}
try {
if (snapshot.val().services != undefined) {
this.setState({
selectedOptionSerivce: snapshot.val().services,
});
}
} catch {}
try {
if (snapshot.val().home_service != undefined) {
this.setState({
selectedOption: snapshot.val().home_service,
});
}
} catch {}
Now is there a more robust and efficient way to achieve this?
Some way to update all the states at once and not crash if one of the state has its value as undefined or simply fails. So that way, the states that run into no problems, get updated, but the states that run into exceptions and errors, simply get discarded without showing any error.
so it will be something like this:
field 1: STRING ->> state updated
field 2: STRING ->> state updated
field 3: STRING ->> state updated
field 4: STRING ->> state updated
field 5: undefined ->> state update FAILED (an array of objects was excepted)
NOTICE: this question is not limited to firebase, its about setState
handling exceptions and errors of all kind.
Upvotes: 0
Views: 524
Reputation: 4435
First, you don't need to wrap this.setState
inside of a try/catch
. setState
will not throw an error if you try to set some property of your state to undefined
- this is definitely allowed.
class App extends React.Component {
constructor(props) {
super(props);
this.state = { foo: "bar" };
}
componentDidMount() {
setTimeout(() => {
this.setState({
foo: undefined
});
}, 4000);
}
render() {
return this.state.foo !== undefined ? (
<h1>this.state.foo is not undefined</h1>
) : (
<h1>this.state.foo IS undefined</h1>
);
}
}
ReactDOM.render(
<App />,
document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
So, when you say that it "fails" because you set a piece of state
to undefined
, you're most likely not handling this case elsewhere in your code. This is common when you're expecting something to be an array
and you're trying to use the map
method, but it turns out to be undefined
.
render() {
// this.state.skills is `undefined
// and you're trying to use the `map` method
// which will fail
return (
<div>
{this.state.skills.map(...)}
</div>
)
}
What you should do is to specify fallbacks for items that come back as undefined
:
class App extends React.Component {
updateState = () => {
firebase()
.then(snapshot => {
this.setState({
state_name: snapshot.val().name || '',
state_age: snapshot.val().age || 0,
state_email: snapshot.val().email || '',
state_phoneNumber: snapshot.val().phoneNumber || '',
state_skills: snapshot.val().skills || []
})
})
.catch(/* handle errors appropriately */)
}
}
Upvotes: 0
Reputation: 6086
There is absolutely no sense in doing something like:
try {
if (snapshot.val().home_service != undefined) {
this.setState({
selectedOption: snapshot.val().home_service
});
}
} catch{ }
Calling setState
won't crash if you set undefined
as a value. The only case you may face an error is when you accidentally forgot to check this value inside of a lifecycle methods or render
:
render() {
return this.state.skills.map(...)
}
Here, if skills
is undefined
you'll get an error. For efficiency sake you may do something like:
class Some {
constructor() {
this.state = {...}
}
get skills() {
return this.state.skills || []
}
render() {
return this.skills.map(...)
}
}
Upvotes: 0
Reputation: 17888
You can assign to skills an empty array when it is undefined like this:
this.setState({
state_name: snapshot.val().name,
state_age: snapshot.val().age,
state_email: snapshot.val().email,
state_phoneNumber: snapshot.val().phoneNumber,
state_skills: snapshot.val().skills || [],
});
Upvotes: 1