Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add react example #6

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Add react example #6

wants to merge 1 commit into from

Conversation

bxt
Copy link

@bxt bxt commented Aug 17, 2024

Hello 👋

This pull requests adds an example written with React.

I don't even know if you want to include other approaches and frameworks into your analysis, feel free to just close this if you don't. Mostly I thought it's an interesting perspective and I was curious myself how a React version would look like. So I spend a bit of time to create an equivalent React-based implementation. It renders the very same things, but because React has some different principles, the module boundaries and responsibilities are shifted a bit.

I really wanted to contribute to your examples, because particularly like that the focus of the code here is on rendering, which is what React was originally made for. This allows us to skip many parts which people commonly complain about that make React apps complex:

  • All HTML is entirely created in the browser, we do not look at server rendering. This would complicate thing even further, a server would be required to render the initial HTML. In jQuery terms this would be roughly equivalent to "progressive enhancement" over an app that is e.g. written in PHP, but the example did not put focus on that either, so let's skip that.
  • Other things that make apps more complex are data fetching, management of global state, unit testing, type checking, code splitting, bundling or client side routing. All those are not required in this case so we can keep things rather simple.
  • I did not use JSX, as this would mean the example is no longer written in JavaScript. Using JSX would allow us to write some things more "HTML looking" e.g. <MyApp /> instead of React.createElement(MyApp). But I think in this example it is not needed and would introduce more complexity.
  • When things get more complex and many third party libraries are involved, you'd usually reach for a dependency manager like npm. Here, we can get way with loading React from unpkg.com. I did not want to vendor it into the code to avoid licensing issues, also to keep the git repo small. It boils down to around 60 KB of external resources loaded (compressed) which amounts to around 140 KB (uncompressed) of extra JS to parse, so less efficient than jQuery.

Of course in a larger production app you would probably need to solve all these issues eventually, and the added complexity would add more insights into a jQuery vs. React debate, however, the example would also need to be much larger and harder to keep comparable. There are plenty of projects that cater to a comparison like that, most notably TodoMVC.

Another thing to do differently in a production app are the things mentioned in #2 like using actual <a> tags instead of <span>s for the clickable page numbers. But I decided to stick to how it is implemented in the original solution. It would certainly be not very hard to do those adjustments in React as well.

One thing that comes "for free" with React's virtual DOM diffing approach is that the elements in the DOM stay the same. Compared to using empty() (jQuery) or innerHTML ("ES6") this keeps things like DOM state and focus, and shifts some work from the browser to the library.

A major architectural difference is how components handle their state and communicate with each other. To keep the code as "idiomatic React code", I used a React hook to save the current page number. This makes it impossible to access this state from other components written in e.g. jQuery or ES6, without further adjustments. However, with most React apps, the whole app would be written in React and the interoperability with other components or libraries need to be solved only for exceptional cases.

In case it helps with understanding, I also re-wrote the example to use JSX.

Same code but using JSX syntax
function PagedContent({ id, page }) {
  return (
    <div id={id} className="paged-content">
      Page {page}
    </div>
  );
}

function Pager({ id, pages, page, setPage }) {
  return (
    <div id={id} className="pager">
      <span>Page: </span>
      {new Array(pages).fill(null).map((_, index) => {
        return (
          <span
            key={index}
            onClick={() => {
              setPage(index + 1);
            }}
            className={`page${index + 1 === page ? ' selected' : ''}`}
          >
            {index + 1}
          </span>
        );
      })}
    </div>
  );
}

function MyApp() {
  const pages = 5;
  const [page, setPage] = React.useState(1);
  const pagerProps = { pages, page, setPage };

  return (
    <>
      <Pager id="top_pager" {...pagerProps} />
      <PagedContent id="content" page={page} />
      <Pager id="bottom_pager" {...pagerProps} />
    </>
  );
}

const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<MyApp />);

I am not in any way part of the React team, so this example can only reflect my own opinion on how an example like yours can be reflected with React code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant