skip to Main Content

What is difference in writing in two different ways below?

function App(isTrue){
  if(isTrue)
    return <ComponentA/>
  else
    return <ComponentB/>
}
// what is different if I write like this 
function App(isTrue){
  return(<>
    {isTrue && <Component/>}
    {!isTrue && <ComopnentB/>}
    </>
  )
}

2

Answers


  1. There is no difference, in either case the same jsx – ComponentA will render.

    The reasoning:

    a) isTrue is a truthy value in either case

    // It is an empty object - more specifically
    
    // let us see this below
    
    const isTrue = {}
    
    isTrue ? true : false // will result true
    

    b) The logical && expression, isTrue && Component A, will evaluate true and return the right-side value which is the component Component A.

    c) !isTrue && Component A, will evaluate to a false value, which React will ignore from rendering.

    d) Fragment tag <></> does not have any trace in the resultant HTML

    Login or Signup to reply.
  2. In your case – with different components – there’s no noticable difference, since distinct components do not share state. The returned React elements (i.e. component subtree) from the functions is slightly different, but the rendered HTML will be identical.

    If you desugar the JSX, your components’ implementation (assuming that Component and ComopnentB in the original question are typos; assuming that the function signature is actually App({isTrue}) to match the required signature of React function components) is actually:

    function App({isTrue}) {
      if (isTrue)
        return React.createElement(ComponentA, null);
      else
        return React.createElement(ComponentB, null);
    }
    
    function App({isTrue}) {
      return React.createElement(
        React.Fragment,
        null,
        isTrue && React.createElement(ComponentA, null),
        !isTrue && React.createElement(ComponentB, null),
      );
    }
    

    And inlining those createElement calls:

    function App({isTrue}) {
      if (isTrue)
        return {
          type: ComponentA,
          props: null,
          key: null,
          ref: null,
          $$typeof: Symbol.for('react.element'),
        };
      else
        return {
          type: ComponentB,
          props: null,
          key: null,
          ref: null,
          $$typeof: Symbol.for('react.element'),
        };
    }
    
    function App({isTrue}) {
      return {
        type: Fragment,
        props: {
          children: [
            isTrue && ({
              type: 'ComponentA',
              props: null,
              key: null,
              ref: null,
              $$typeof: Symbol.for('react.element'),
            }),
            !isTrue && ({
              type: 'ComponentB',
              props: null,
              key: null,
              ref: null,
              $$typeof: Symbol.for('react.element'),
            }),
          ],
        },
        key: null,
        ref: null,
        $$typeof: Symbol.for('react.element'),
      };
    }
    

    As you can see, the component tree is vastly different:

    • A single React element, one of two components
    • A React Fragment containing exactly 2 children. Either the first or the second child is false

    Things become more interesting if you introduce state into your ComponentA and render it twice. After all, the question is tagged .

    function CountingButton() {
      const [count, setCount] = useState(0);
      return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
    }
    
    function ComponentA() {
      return <>A <CountingButton /></>;
    }
    function ComponentB() {
      return <>B <CountingButton /></>;
    }
    
    function AppIf({isTrue}) {
      if (isTrue)
        return <ComponentA/>;
      else
        return <ComponentA/>; // same position in component tree
    }
    
    function AppShortCircuit({isTrue}) {
        return (
          <>
            {isTrue && <ComponentA/>}
            {!isTrue && <ComponentA/>} // different position in component tree
          </>
        )
    }
    
    export function Dashboard() {
        const [checked, setChecked] = useState(false);
        return (
            <div>
                <div>
                    <input id="isTrueCheckbox" type="checkbox" checked={checked} onChange={(ev) => setChecked(ev.target.checked)}/>
                    <label htmlFor="isTrueCheckbox">Toggle <code>isTrue</code></label>
                </div>
                <AppIf isTrue={checked}/>
                <AppShortCircuit isTrue={checked}/>
            </div>
        );
    }
    

    If you click the checkbox to toggle the isTrue prop of your nested components, you will notice that the state of ComponentA inside AppShortCircuit will be reset, but the state of the component inside AppIf is retained. This is because state is tied to a position in the render tree.

    • AppIf is effectively rendering the same tree, regardless of the prop’s value. Both components are rendered in the same position, so they share state.
    • AppShortCircuit is either rendering [false, ComponentA] or [ComponentA, false]. The components do not share the same position in the tree and consequently do not share state.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search