AlexGilleran / jsx-control-statements

Neater If and For for React JSX
https://www.npmjs.com/package/babel-plugin-jsx-control-statements
MIT License
1.62k stars 64 forks source link

Switch-case style control statement #111

Closed ShaharMintzRiversideFM closed 2 years ago

ShaharMintzRiversideFM commented 2 years ago

I love what you're doing here and started using jsx-control-statements in some of our projects. I have a suggestion for a useful (in my opinion) addition. <Choose> is great for any kind of condition set, but in practice, many times we render according to the value of one expression (the classic switch-case).

What are your thoughts regarding supporting that switch-case scenario, which would look something like the following?

<Switch value={status}>
  <Case is={'active'}>
      <Active />
  </Case>
  <Case is={'pending'}>
      <Pending />
  </Case>
  <Case is={'not-active'} isDefault>
      <NotActive />
  </Case>
</Switch>

We've creating this with simple React but of course using transformation would be much better.

export const Switch: React.FC<{ value: any }> = ({ value, children }) => {
    return useMemo(() => {
        let defaultChild = null;
        for (const child of ensureArray(children)) {

            if (child.type !== Case) {
                continue;
            }

            if (child.props.is === value) {
                return child;
            }

            if (child.props.isDefault) {
                defaultChild = child;
            }
        }
        return defaultChild;
    }, [value, children]);
};

export const Case: React.FC<{ is?: any; isDefault?: boolean }> = ({
    is = undefined,
    isDefault = false,
    children,
}) => {
    return <>children</>;
};
AlexGilleran commented 2 years ago

Personally I'm not really in favour of adding any new statements to this project - I'm happy to keep it going as long as it helps people, but like I say at the top of the readme, this was conceived when JSX was very new and so adding another layer of transformation on top of it didn't seem like such a big deal. Now there's a lot of tooling (particularly typescript) that expects JSX to be a certain way, and we've got new patterns in react that solve these problems in a way that's only marginally less neat but works without any transformation.

For this case, I think a render props implementation like

<Switch value={status}>
  <Case is={'active'}>
      () => <Active />
  </Case>
  <Case is={'pending'}>
      () => <Pending />
  </Case>
  <Case is={'not-active'} isDefault>
      () => <NotActive />
  </Case>
</Switch>

Would be possible without any transformation, give you what you want in terms of not evaluating what's in the blocks if not needed, and also work with any extra tooling you wanted to throw at it.

If you really wanted to make it into a transform, it would be easy enough to fork the babel boilerplate in this repo and then implement this component on top of it :).

ShaharMintzRiversideFM commented 2 years ago

@AlexGilleran, thanks for the serious answer and the suggestions! I just might try to make a transform :)