1

Let's consider a simple @wire example:

@wire(getRecord, { recordId: '$recordId', fields: RECORD_FIELDS })
wiredRecord({ error, data }) {
    if (data) {
        doStuff();
    } else if (error) {
        console.error(error);
    }
}
  1. Every example I see has if (data) and else if (error). Is it guaranteed that you cannot run into a non-existent else? In this form, the pattern gives me the vibe that something is missing.
  2. Why is this not generally written as a guard clause but an if / else if instead? e.g.
if (error) {
    console.error(error);
    return;
}

if (data) {
    doStuff();
}
  1. Written like this - what cases actually need to be checked with if (data)? Isn't it enough to just check for errors?

Generally, I think I prefer the guard clause example above - so I wonder why nobody uses it. Maybe this is just an LWC "pattern" and it would be written differently in a non-LWC JavaScript world?

2 Answers 2

2

WARNING: some opinion in here

The response from a wire is one of {}**, {data: x} or {error: y}. You never receive {data: x, error: y}.

Because you can receive that empty object the if (data) {...} else if (error) {...} handles all possible (real world rather than conceptual) options cleanly (you don't need to do data or error handling if there's no value for either).

Stylistically I prefer the function to cover what happens in the happy path first, leaving the error handling at the end (somewhat like you would see with a try {...} catch {...}).

**: Your wire function is always called this way before any other calls. I don't really know why, just that this happens.

1
  • 1
    Straightforward answer. Thanks!
    – Semmel
    Commented Mar 25 at 15:12
1

Every example I see has if (data) and else if (error). Is it guaranteed that you cannot run into a non-existent else? In this form, the pattern gives me the vibe that something is missing. ... Why is this not generally written as a guard clause but an if / else if instead? e.g.

There are three possible scenarios.

The first is the "default" provisioning. This data will be in the form of { hidden: wireHandlerData, data: undefined, error: undefined }. I don't actually know what the hidden parameter is, but it is the secret sauce that makes refreshApex work. Note that this is different than { hidden: wireHandlerData } in the sense that the keys are defined, but set to the value undefined. You should only ever see this state once, upon initialization.

The second scenario is when there is data provisioned, which will always be in the form of { hidden: wireHandlerData, data: readOnlyData, error: undefined }. In this case, the wire method finished successfully and has some kind of data for you. However, remember that null can be a potentially valid value.

The third scenario is what you get if an uncaught exception is thrown. In this case, you get { hidden: wireHandlerData, data: undefined, error: readOnlyData }. In this scenario, error will never be null and data will always be undefined.

There's no further scenarios. There's no need for the else; you can just use a guard, as you suggest. In fact, that's what I do in modern code. I don't think I'd qualify as a "never nester," but I do intentionally try to restrict indentation to no more than about 4 levels (class, method, for/try/if/do/while, try/if/do/while). It's rare to see indentation above 5, unless I'm using Prettier, and even then, I still minimize indentation as much as possible. Beyond that, I use additional methods/functions to keep the code readable.

Generally, I think I prefer the guard clause example above - so I wonder why nobody uses it. Maybe this is just an LWC "pattern" and it would be written differently in a non-LWC JavaScript world?

The documentation is written for people who have some development experience, but not a lot. You'd expect someone with six months of development to write the typical block of code. "Advanced" techniques like guard statements don't appear anywhere in the documentation, and I believe this is intentional. Technical writers presumably want the documentation to be accessible to as many people as possible, even those that may be brand new to programming itself.

That said, I am a strong proponent of consistent coding styles. If a project is already using guards, I'll use guards. If they're using if-else, I'll use if-else. For my own projects, I typically use guards, because they tend to optimize code coverage and are easier to read.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .