[HN Gopher] Advice on JSX Conditionals
       ___________________________________________________________________
        
       Advice on JSX Conditionals
        
       Author : fagnerbrack
       Score  : 86 points
       Date   : 2022-03-08 06:15 UTC (1 days ago)
        
 (HTM) web link (thoughtspile.github.io)
 (TXT) w3m dump (thoughtspile.github.io)
        
       | horsawlarway wrote:
       | Most of these are just "tips on using conditionals" and have very
       | little to do with JSX itself.
        
         | sfvisser wrote:
         | True. Also many of these are not actual issues and are just
         | behavior inherent to using JavaScript.
         | 
         | If you don't like your conditional logic in your template just
         | give them a name and explicit boolean type and be done with it.
         | 
         | Still a useful overview of common idioms though for people who
         | just get started.
        
           | horsawlarway wrote:
           | > Still a useful overview of common idioms though for people
           | who just get started.
           | 
           | I agree - I just think labeling them as JSX issues is pretty
           | disingenuous. JSX is literally just running them as standard
           | js expressions here - which I actually find delightful: they
           | work the same as they do in normal javascript (quirks
           | included :D ).
           | 
           | The author seems to want something like ng-if="condition",
           | and I find DSLs in this space a real abomination.
        
       | Eric_WVGG wrote:
       | Drives me nuts that there's no straightforward way to do a switch
       | statement in JSX.                 <Layout>         <Header />
       | {switch (page) {           case 'home': return <Home />
       | case 'about': return <About />           default: return
       | <NotFound />         }}         <Footer />       </Layout>
        
         | 9wzYQbTYsAIc wrote:
         | The example you put forward could be resolved through using a
         | router. The router implementations are essentially fancy
         | switches without "switch".
        
           | Eric_WVGG wrote:
           | yeah, I use reach/router for this kind of thing. A page
           | switcher was just the first example that popped into my head.
           | 
           | Here's a real world example if it matters...
           | const Grid = (gridItems) => (         <Grid>
           | {gridItems.map(item => (             <GridItem {...item}
           | key={item._key} />           _}         </Grid>       )}
           | const GridItem = (props) => {         switch(props._type) {
           | case 'image': return <GridImage {...props} />           case
           | 'video': return <GridVideo {...props} />           case
           | 'copy': return <GridCopy {...props} />           //
           | slideshows, 3D stuff, newsletter signup forms...
           | default: return <></>         }       }
           | 
           | ... and I suppose a case could even be made for the
           | granularity of this superfluous <GridItem /> component... but
           | regardless this is just a minor annoyance that comes up from
           | time to time.
        
             | methyl wrote:
             | I'd write it like this                 const gridComponent
             | = {           image: GridImage,           video: GridVideo,
             | copy: GridCopy       }            const Grid = (gridItems)
             | => (         <Grid>           {gridItems.map(item => {
             | const GridComponent = gridComponent[item._type]
             | return GridComponent ? <GridComponent {...item}
             | key={item._key} /> : null           }}         </Grid>
             | )}
        
               | 9wzYQbTYsAIc wrote:
               | That's definitely representative of the compactness that
               | is possible with modern JSX.
        
         | bern4444 wrote:
         | I'm surprised this doesn't work since you could easily
         | externalize this to a function:                 <Layout>
         | <Header />         {getCorrectComponent(page)}         <Footer
         | />       </Layout>            const getCorrectComponent =
         | (page) => {         switch (page) {           case 'home':
         | return <Home />           case 'about': return <About />
         | default: return <NotFound />         }       }
        
           | uhoh-itsmaciek wrote:
           | Yeah, this is generally a good compromise. I sometimes like
           | to write these as helper components instead:
           | <Layout>         <Header />         <Content page={page} />
           | <Footer />       </Layout>            const Content =
           | ({page}) => {         switch (page) {           case 'home':
           | return <Home />           case 'about': return <About />
           | default: return <NotFound />         }       }
        
           | Eric_WVGG wrote:
           | that does work. imo ugly, not straightforward
        
         | hombre_fatal wrote:
         | You could of course wrap the switch in a self-invoking
         | function: {() => { switch... }()}
         | 
         | Sometimes an inline switch is indeed the clearest code. The
         | closest JS has is the do-expression proposal: { do { switch...
         | }}
        
       | Kaotique wrote:
       | I actually really like the nested ternaries. TypeScript
       | understand them very well and you don't have to extract your code
       | outside the render to start using if/else structures. They also
       | format quite well.
        
         | eyelidlessness wrote:
         | I like ternary conditionals, nested or otherwise. But I also
         | like reduce. And regular expressions. And I know a lot of other
         | devs hate some or all of them. So I tend to use them sparingly
         | when working with a team... although I do see more ternaries in
         | idiomatic code these days, generally as devs embrace a more FP
         | style.
        
       | laurent123456 wrote:
       | I think a better approach is to move the logic to a renderXxx()
       | function:                   function renderInput(props:Props) {
       | // Early exit if props are not as expected             if
       | (!props.cond1) return null;             return <JSX/>;         }
       | 
       | Then the parent markup is much cleaner, without any conditional:
       | {renderInput(props)}
        
         | dimgl wrote:
         | This pattern is fine, but I would make this a component.
         | function ConditionalComponent(props: Props) {           if
         | (!props.condition) return null           return
         | <UnderlyingComponent {...props} />         }
        
         | hombre_fatal wrote:
         | Though you're also adding indirection.
         | 
         | Not always worth it when you're just trying to do some
         | conditional logic next to the code/components that it's related
         | to.
         | 
         | Ideally we have the tools to decide when to add indirection
         | ourselves instead being forced to do it to deal with
         | complexity. You could also see this in callback-hell when we'd
         | flatten callback trees with indirection--the tree looked
         | flatter in the editor but we just moved code around.
         | async/await gave us the tools to decide when we actually wanted
         | it.
        
           | eyelidlessness wrote:
           | How is that indirection? These are semantically identical:
           | {renderIf(foo)}         <RenderIf foo={foo} />
           | 
           | The latter is a bit more _verbose_ , sure, but it's both more
           | idiomatic and a better optimization target.
        
       | phelm wrote:
       | Thanks, this is really useful.
       | 
       | I've been using this Babel plug-in found it quite intuitive
       | 
       | https://github.com/AlexGilleran/jsx-control-statements
        
       | maxwellg wrote:
       | There's a babel plugin for adding an Angular-style "display-if"
       | to JSX - https://www.npmjs.com/package/babel-plugin-jsx-display-
       | if
       | 
       | I've only seen it used in projects once or twice but it really
       | does wonders for readability once the team becomes OK with the
       | new-ish syntax
        
       | latchkey wrote:
       | The more conditional logic you have in a component, the harder it
       | is to write tests for.
        
         | eyelidlessness wrote:
         | Agreed. This is also true for functions and _especially true_
         | for stateful classes /objects.
        
       | tuyiown wrote:
       | I've learnt most of those the hard way, event though TSX is a
       | great safe guard because I tend to slip.
       | 
       | I find funny the persistance in sidestepping a `.length > 0` at
       | all costs.
        
         | eyelidlessness wrote:
         | Personally I _hate_ implied casting of booleans (and implied
         | casting generally), and go out of my way to make boolean checks
         | explicit whenever I touch the code. These kinds of shortcuts
         | made some sense when minification was commonly a manual thing.
         | But now, I want code to be as verbose as necessary for it to be
         | unambiguous.
        
       | beaconstudios wrote:
       | protip: you can use an IIFE (immediately invoked function
       | expression) to put whatever conditionals or logic you want inside
       | JSX! I use this all the time and it's much nicer for more complex
       | blocks:                   {(() => {           switch(state) {
       | case 'loading': return <Loading />;             case 'ready':
       | return <Component />;             case 'error': return <Error
       | error={error} />;           }         })()}
        
         | [deleted]
        
         | [deleted]
        
         | bacro wrote:
         | Waste of memory by creating new function objects on each
         | render.
        
           | erikpukinskis wrote:
           | Won't V8 just optimize this anyway? I doubt there's any real
           | difference in memory usage.
        
             | bacro wrote:
             | I am not sure, it has a closure for the 'error' local
             | variable.
        
           | beaconstudios wrote:
           | Micro-optimisations aren't useful. If you get to the point
           | where the performance cost of inline functions is a
           | bottleneck, you probably shouldn't be using React at all.
        
             | bacro wrote:
             | Maybe, but I just prefer to have a named function defined
             | with a useCallback and just call it.
        
               | beaconstudios wrote:
               | That's fine, but that's more of a stylistic preference
               | than a performance concern.
        
           | symlinkk wrote:
           | Yeah probably best to move this to a function outside the
           | render loop with useCallback
        
         | masterofmisc wrote:
         | Oh, I like this. Thanks.
        
       | the_gipsy wrote:
       | Nice article.
       | 
       | To me it boils down to one JS problem: Lacking `if` expression,
       | and one React problem: Side effects of un/mounting.
        
       | LAC-Tech wrote:
       | IMHO this is an anti-pattern.
       | 
       | This involves people writing giant blocks of JSX that are hard to
       | read. Especially with && all over the place. Just split up your
       | component into smaller components with max one conditional each.
       | 
       | Related, can anyone tell me the origins of the bizarre react
       | practice of one file per component? I'm assume some mega corp
       | told people it was "best practice", but the end result is way too
       | many files with hard to read components.
        
         | conradludgate wrote:
         | I'm assuming it dates back to class components and Class per
         | File ideologies
        
           | LAC-Tech wrote:
           | Interesting! And yeah Class per file had the exact same
           | problem - classes were big and did too much. And now everyone
           | hates "OO"
        
       | jeffalbertson wrote:
       | its rare but im ok with a nested ternary when its being passed
       | down as a prop. dont wanna use a function in that situation.
       | 
       | sidenote - I discovered vladimirs blog a while back and love it.
       | high quality content
        
       | eyelidlessness wrote:
       | It doesn't necessarily have the same benefits in React, but folks
       | ought to consider using components for control flow, like SolidJS
       | does[1].
       | 
       | 1: https://www.solidjs.com/docs/latest/api#control-flow
        
         | dimgl wrote:
         | Funnily enough, this has existed in React through a Babel
         | plugin. I'm not sure why this hasn't really caught on.
         | 
         | https://github.com/AlexGilleran/jsx-control-statements
        
           | eyelidlessness wrote:
           | I've encountered that, and kind of don't understand why you'd
           | need a Babel plugin. They're trivial components to implement
           | in regular JSX.
        
         | latchkey wrote:
         | Some people consider this added complexity?
         | 
         | https://news.ycombinator.com/item?id=30509806
        
           | eyelidlessness wrote:
           | I mean, sure. But compilers often impose complexity as a
           | trade off for performance or other benefits.
        
         | tdumitrescu wrote:
         | Control-flow components like "<For>"... because you couldn't
         | stand just writing "for" or "if" like a caveman and had to
         | invent a custom DSL for it.
        
           | eyelidlessness wrote:
           | Solid actually uses them for static analysis which ~isn't
           | otherwise possible in JSX, which has to be an expression. It
           | would be great if for/if were expressions in JS, but they're
           | not.
        
         | kipple wrote:
         | Agreed. I particularly like the look of their
         | `<Switch>/<Match>` component[1]:                 <Switch
         | fallback={<div>Not Found</div>}>         <Match
         | when={state.route === "home"}>           <Home />
         | </Match>         <Match when={state.route === "settings"}>
         | <Settings />         </Match>       </Switch>
         | 
         | Which doesn't seem to have an analog in the React babel-
         | plugin[2] or standalone lib[3]
         | 
         | [1]
         | https://www.solidjs.com/docs/latest/api#%3Cswitch%3E%2F%3Cma...
         | 
         | [2] https://github.com/AlexGilleran/jsx-control-statements
         | 
         | [3] https://github.com/samuelneff/react-control-flow
        
         | Eric_WVGG wrote:
         | That's pretty slick.
        
       | nkohari wrote:
       | I've always much preferred using local variables to hold
       | conditional fragments. Since React will safely ignore
       | null/undefined, you can do:                 let child;       if
       | (someCondition) {         child = <SomeComponent ... />;       }
       | return (         <div>           Maybe here's a child: {child}
       | </div>       );
       | 
       | This lets you avoid embedding conditional logic in your (already
       | pretty dense) JSX tree.
        
         | postalrat wrote:
         | I do this sometimes but having to look up where child was
         | defined and everything that could have changed it can be
         | tiresome.
         | 
         | That's why a function can be better, at least you know that the
         | value isn't changed somewhere unexpected.
        
       | TameAntelope wrote:
       | I just avoid most of it by moving the complex conditional logic
       | into a separate component and rendering that.
       | 
       | I don't think I've run into many issues with this strategy, and
       | keeps my return statements nice and clean.
        
         | vlunkr wrote:
         | Agreed, if it's more complex than a single ternary, or &&
         | statements, make a new component.
        
         | matt-attack wrote:
         | I find ternaries alone to be totally adequate.
        
           | TameAntelope wrote:
           | Oh they work, but stacking them tends to make future reading
           | of the code harder due to their increased complexity.
        
             | kingdomcome50 wrote:
             | Nested ternaries can by structured to look a look like
             | `if/else` if you put the `?/:` in the right spots.
             | 
             | It's a balance. Extracting logic into new components (and
             | often new files!) isn't exactly ergonomic either.
             | 
             | I've found it's _better_ to decrease readability if it
             | makes understanding the _logic_ more straight-forward (i.e.
             | not hunting through several files to exhaust all possible
             | outputs).
        
       | tobr wrote:
       | Hard disagree on nested ternaries, or rather _chained_ ternaries,
       | which are just as easy to read and reason about as chained if
       | else statements:                 if (isA) {         return A;
       | } else if (isB) {         return B;       } else if (isC) {
       | return C;       } else {         return D;       }
       | 
       | is equivalent to                 return isA ? A : isB ? B : isC ?
       | C : D;
        
         | dimgl wrote:
         | Sure, when you're neatly using booleans with names that are
         | three characters long, this is super easy to parse.
         | 
         | Now throw in long functions with multiple arguments, and all
         | kinds of different access patterns and this ternary starts to
         | look like a nightmare.
        
           | akvadrako wrote:
           | It's still often the cleanest way and I find myself doing
           | something like this:                 let x =
           | somelongfunc(arg, blah(etc))                  ? value1
           | : some other condition                  ? value2
           | : fallback
           | 
           | What I usually want is pattern matching expressions, but
           | those are not in many languages.
        
             | brimble wrote:
             | Try as I might, I have to reason through ternaries every
             | time I encounter them. I think the = being so removed from
             | what it's actually assigning, but without grouping parens,
             | is what messes me up. Plus I always forget what the
             | punctuation characters mean--if/elseif/else uses words, so
             | I don't have to remember.
        
               | eyelidlessness wrote:
               | > I think the = being so removed from what it's actually
               | assigning, but without grouping parens, is what messes me
               | up.
               | 
               | I almost always use grouping parentheses for this reason,
               | unless it's a _very_ short single line expression. That
               | said, if /else if/else has a different colocation
               | problem: it puts the assignment further from the initial
               | declaration, making its scope less obvious (unless you're
               | hoisting var, which is awful for its own reasons).
        
               | brimble wrote:
               | Agree, the problem with if/else is that you end up having
               | to consider the whole block plus usually a little context
               | from just before it. I still find it much easier to read,
               | unless very poorly written, while all ternaries slow me
               | down _every single time_ I read one, no matter how well-
               | written. I struggle to parse them into ideas and words
               | and to follow the order of events, seemingly no matter
               | how many times I encounter them. They just feel _wrong_.
               | All that implicit scoping crammed into one line, relying
               | on memory and active searching to find the boundaries and
               | then follow the order of events back  "to the top",
               | rather than having them explicitly marked.
        
               | erikpukinskis wrote:
               | Yeah, I think nested ternaries are fine as long as it's
               | just a list like OP is suggesting...
               | 
               | But it breaks peoples brains for some reason so I rarely
               | use them professionally.
               | 
               | It's really not that hard though, the ? and : are just
               | shorthand for "else if" and "then".
        
               | tobr wrote:
               | Just read whatever has a question mark after it with the
               | intonation of a question, and it flows naturally.
        
         | dlbucci wrote:
         | Especially if you format them well. Just use a newline before
         | each `:` and maybe after each `?` (if the value expressions are
         | large), and it'll look great.                 return isA ? A
         | : isB ? B         : isC ? C         : D
        
           | bluefirebrand wrote:
           | This looks fine as an example right here, but it starts to
           | look terrible if there's larger or multiline boolean
           | expressions involved, while if/else if winds up still being
           | pretty readable.
        
         | smt88 wrote:
         | I have been writing code in C-like languages since 1996 and I
         | find the ternary equivalent to be unreadable.
         | 
         | If you're ever doing this in any language with simple if()
         | conditions, you need to refactor anyway.
        
       | phailhaus wrote:
       | When logic gets more complicated than a single ternary (e.g.,
       | handling pending/error/result state), I've found that a `useMemo`
       | gives me the flexibility I need. It also keeps the messy logic
       | out of the final JSX, which tends to make it read better.
        
         | heyparkerj wrote:
         | I've personally rarely even needed to useMemo, I just write a
         | function that returns the JSX I need and { myFunction() } in
         | the functional component's return (given React).
        
           | phailhaus wrote:
           | If you're using Typescript that can get a bit annoying, since
           | you'll also need to pass in whatever props necessary for the
           | function to handle the logic + type them. Makes it nice and
           | easy to test in isolation though.
        
             | heyparkerj wrote:
             | Typically the function has access to whatever props or
             | state it needs because it's in the scope of the component.
             | It's not pure, but it's rare that I need to verbosely pass
             | props into the function call and then accept them in
             | myFunction. I don't typically test these functions in
             | isolation as the component itself is pure and I test the
             | output of the component as a whole instead.
        
               | phailhaus wrote:
               | Oh gotcha, I thought this was a function that was defined
               | outside of the component.
        
         | 9wzYQbTYsAIc wrote:
         | The React maintainers did put a lot of effort into making
         | hooks. The variety of hooks seem to cover all the use cases for
         | programming.
        
       | molf wrote:
       | I've always found these approaches to writing conditions in JSX
       | to be terrible. Wouldn't it be nice if JavaScript were an
       | expression-oriented language? Then you could just write:
       | {if (gallery.length) {            <Gallery slides={gallery}>
       | }}
       | 
       | There has been a "do expressions" proposal [0] for many years,
       | which addresses this (though it is more verbose). I hope it will
       | be accepted some day.
       | 
       | [0] https://github.com/tc39/proposal-do-expressions
        
         | threeys wrote:
        
         | wa1987 wrote:
         | For these situations I often use IFFEs with if-statements and
         | early returns inside.
        
         | jkcxn wrote:
         | Yes Dart with Flutter and swift UI both had to add language
         | features just to support if and loop expressions. But people
         | writing immediate mode guis have been doing the exact same
         | thing using standard language features for years. There's no
         | reason you can't mix React-ive style components with an
         | immediate style API. I do this in a GUI library I've written in
         | D. The downside is you get slightly less type safety, but I'm
         | happy to pay that cost
        
           | favorited wrote:
           | > swift UI both had to add language features just to support
           | if and loop expressions
           | 
           | The special syntax for loops in SwiftUI is important, because
           | plain-old loops are always eager. For example, if you were
           | building building a list using a loop, it would iterate over
           | every item up-front to generate the list's body. With the
           | `ForEach` struct, on the other hand, you provide the block to
           | create each item, and it can be invoked lazily as the content
           | will appear.
        
         | 9wzYQbTYsAIc wrote:
         | From the article:
         | 
         | "{number && <JSX />} renders 0 instead of nothing. Use {number
         | > 0 && <JSX />} instead."
         | 
         | Functional JSX would look like:
         | 
         | const isNumber = number > 0;
         | 
         | {isNumber && <JSX />}
         | 
         | You can similarly do things like:
         | 
         | const isVisible = condition1 && (condition2 || condition3) ||
         | guard(props.input1);
         | 
         | {isVisible && <JSX />}
         | 
         | The functional paradigm and some basic code factoring can make
         | quick work of conditional JSX
        
           | molf wrote:
           | Yes, I'm well aware of how to use these. I will elaborate on
           | why I think it's terrible (even though there is no
           | alternative in standard JS yet):
           | 
           | * It encourages JSX-specific idioms. Outside of JSX, using
           | `&&` instead of `if` for control flow would raise eyebrows
           | from most people, I think.
           | 
           | * I find it easier and faster to refactor `if` statements to
           | `if/else` and vice versa (only requires addition or deletion
           | of code) than to refactor `&&` to a ternary operator and vice
           | versa (also requires modifying existing code).
           | 
           | * Multiple nested ternary operators almost immediately become
           | a mess, while a series of `else if` expressions (if such a
           | thing existed) seem perfectly readable.
        
             | 9wzYQbTYsAIc wrote:
             | It's generally better to go with the idioms of the
             | language, sure, but in this case, the idioms of JSX work
             | well and they are future-proof. If JavaScript adds the
             | support that you are looking for, it would be easy enough
             | for a static code analyzer to rewrite "&&" as "if"
        
             | hombre_fatal wrote:
             | You can add do-expression proposal support in .babelrc:
             | <div>         {do {           if (user) {
             | <Logout />           } else {             <Login />
             | }         }}         </div>
             | 
             | https://babeljs.io/docs/en/babel-plugin-proposal-do-
             | expressi...
        
               | Izkata wrote:
               | Or, no need to enable anything:                 {user
               | ? <Logout \>           : <Login \>       }
        
               | couchand wrote:
               | Ok this thread just reached peak JavaScript.
        
               | christophilus wrote:
               | Ternary expressions have been around long before
               | JavaScript was a twinkle in Brandon Eich's eyes.
        
               | 9wzYQbTYsAIc wrote:
               | Just modern ECMA Script, not peak JavaScript. ES6 and
               | React Hooks have fully sublimated the web development
               | landscape.
        
             | jameshart wrote:
             | Why do you think of JSX's use of && as control flow?
        
               | eyelidlessness wrote:
               | Can't speak for GP, but for me, because:
               | { someBool && <Anything /> }
               | 
               | ... only renders <Anything /> if someBool is true.
        
               | [deleted]
        
               | jameshart wrote:
               | What if you consider it as 'only returns a data structure
               | that requests the rendering of <Anything /> if someBool
               | is true'?
               | 
               | If you write                   console.log(someBool &&
               | "anything")
               | 
               | Are you altering the control flow because the console
               | window will call a different bit of font evaluation code
               | to render "anything" instead of "false"?
               | 
               | Or are you just conditionally evaluating an expression
               | that results in different data that causes different
               | downstream effects?
               | 
               | Evaluating <Anything/> doesn't _do_ anything. It doesn't
               | make any DOM elements. It doesn't trigger any useEffects.
               | It just returns an object that has the potential to be
               | hooked into a react renderDOM lifecycle to provide
               | further instructions on what the DOM should look like and
               | what other core should run.
        
               | 9wzYQbTYsAIc wrote:
               | and if that expression-body is wrapped within the
               | render() method.
        
               | eyelidlessness wrote:
               | Okay: only _evaluates_ <Anything /> if someBool is true.
               | The value of someBool quite literally controls which code
               | path is taken. It's even more clear with a fallback:
               | { someBool && <Anything /> || <Fallback /> }
               | 
               | Which would more idiomatically be written as a ternary
               | conditional, but still. It doesn't matter where the
               | expression is placed, it's the same if you assign it to a
               | variable:                   const el = someBool &&
               | <Anything /> || <Fallback />;
               | 
               | Or even just as an expression statement:
               | someBool && <Anything /> || <Fallback />;
        
               | 9wzYQbTYsAIc wrote:
               | > It doesn't matter where the expression is placed, it's
               | the same if you assign it to a variable
               | 
               | If you separate the concern of the condition definition
               | from the conditional rendering, by pulling the
               | conditional's definition into a variable, you do get
               | enhanced portability, though.
               | 
               | Much easier to port between languages and frameworks if
               | your conditional definition can be copy-and-pasted out
               | without having to mess with untwining the previous
               | developers expression statements.
        
               | eyelidlessness wrote:
               | I'm not sure whether I agree or disagree with this. But I
               | do want to clarify that my intent was not to argue for or
               | against conditional expressions in any code position,
               | only to address the factual question of whether they
               | constitute control flow.
        
               | jameshart wrote:
               | But the short circuiting doesn't _matter_.
               | 
               | You could go                  let x = <Anything />;
               | return someBool && x;
               | 
               | And the result (assuming well behaved react code) would
               | be the same. <Anything /> is just a literal expression.
               | It doesn't matter whether it gets evaluated or not.
               | 
               | You're not using && shortcircuiting to _prevent
               | <Anything/> from being evaluated_ - it doesn't matter if
               | it gets evaluated. You are using it to decide which value
               | to return.
               | 
               | This really isn't 'using shortcircuiting for control
               | flow'. It's just using && as an operator in an expression
               | evaluation.
        
             | tshaddox wrote:
             | > Outside of JSX, using `&&` instead of `if` for control
             | flow would raise eyebrows from most people, I think.
             | 
             | Very much so, at least for me. Relying on the short-
             | circuiting of logical operators is fine, but only when
             | you're actually going to use the resulting value. In the
             | case of JSX, this is relying on the fact that `false` is a
             | valid React child which renders nothing. Not only does this
             | result in a mistake when the `&&` expression returns
             | something like `0` that is falsey but _isn 't_ `false`, IMO
             | it's already pretty awkward even if you are rendering
             | `false`. I'd honestly prefer a runtime error, just like you
             | get if you try to render a JS object, and only support
             | rendering null and maybe undefined as React children.
        
               | 9wzYQbTYsAIc wrote:
               | > I'd honestly prefer a runtime error, just like you get
               | if you try to render a JS object
               | 
               | The React framework strives for catching everything at
               | compile-time. Runtime errors are a big no-no in web
               | development.
               | 
               | If I recall correctly, rendering null is behaviorally
               | equivalent to not rendering, in React.
        
               | tshaddox wrote:
               | > The React framework strives for catching everything at
               | compile-time. Runtime errors are a big no-no in web
               | development.
               | 
               | I don't know whether that principle is generally true or
               | ought to be generally true, but React _does_ throw a
               | runtime error if you render a plain JS object as a React
               | child. This can probably _also_ be prevented at compile
               | time with linters or TypeScript, but given that React has
               | to do _something_ at runtime if it encounters an invalid
               | child, I think throwing an error is preferable to just
               | rendering nothing or having some undefined behavior.
               | 
               | In my opinion, rendering `null` is a pretty clear and
               | explicit way to indicate you don't want to render
               | anything. But rendering `false` (or `true`, for that
               | matter) is not at all so clear to me. I think throwing a
               | runtime error would be better, and would largely make the
               | `thing && <Component />` idiom go away.
        
               | 9wzYQbTYsAIc wrote:
               | I get what you are saying. In my experience, it ends up
               | being moot when you are explicitly trying to avoid
               | runtime errors, because you'll need something along the
               | lines of "guard() && <Component />" or you could simply
               | have "<Component />" and then within Component render
               | have "if (!guarded) return <Fragment />", etc.
               | 
               | At that point, you'll probably need to worry about
               | component collections containing empty elements, though.
               | That pulls you back into the parent scope, anyways.
               | 
               | There's probably a nicer way to handle it with custom
               | hooks, though.
               | 
               | > I don't know whether that principle is generally true
               | or ought to be generally true
               | 
               | They sure do go out of their way to make misuse of hooks
               | a compile-time error. I think that those useful error
               | messages go a long way to rectifying the archaic
               | semicolon error messages of the C days.
        
           | redler wrote:
           | Another quick option for avoiding the "zero" issue:
           | {!!number && <Thing />}
        
             | 9wzYQbTYsAIc wrote:
             | One of the joys of JavaScript, right there: not-not sorry.
        
             | dbetteridge wrote:
             | Better to use Boolean(number)
             | 
             | Its more obvious what it achieves just at a glance.
        
               | postalrat wrote:
               | "!!" should be pretty obvious to any javascript
               | developer.
        
               | dbetteridge wrote:
               | It might be, but not everyone knows js and I don't expect
               | future people to be me.
               | 
               | More obvious and more readable is always better
        
               | 9wzYQbTYsAIc wrote:
               | Nonetheless, better for the industry if we start to
               | embrace more uniformity in our idioms.
               | 
               | You can practically copy-and-paste between JavaScript and
               | C# these days, with some trivial text replacement tweaks,
               | if you are careful with your idioms.
        
               | postalrat wrote:
               | What if you wanted to get the boolean value of number but
               | with not.
               | 
               | Would you write: !Boolean(n)
               | 
               | Or would you write: !n
        
               | 9wzYQbTYsAIc wrote:
               | if it were C#, I'd write it along the lines of !(n as
               | bool), but for the purposes of JS, I suppose something
               | like:
               | 
               | const IsNumber = (value) => Boolean(value);
               | 
               | !IsNumber(n)
               | 
               | I'm not a fan of using the return-type as the function
               | name, especially when you are really just trying to find
               | out if something is a number.
        
       | sabertoothed wrote:
       | I missed a v-if in react/JSX. My code is so hard to read in JSX.
        
         | eyelidlessness wrote:
         | This is usually a good indicator that your components may be
         | doing too much. If your component's JSX _specifically_ is hard
         | to read, you probably have multiple components implemented
         | within one.
        
       | ryanto wrote:
       | Great article!
       | 
       | I will say I've found that using prettier makes nested ternaries
       | much more readable.
       | 
       | I couldn't imagine using them without prettier, but since every
       | app I work on these days uses prettier nested ternaries aren't so
       | bad.
        
       ___________________________________________________________________
       (page generated 2022-03-09 23:02 UTC)