4 ms·
Like others have said - I think the documentation glosses over how the "rerender" function totally and drastically changes this from a "React alternative" to "b
by daveidol 6y ago
Like others have said - I think the documentation glosses over how the "rerender" function totally and drastically changes this from a "React alternative" to "backbone with JSX".
The point of React is not the JSX, but rather the unidirectional data flow and automatic re-renders due to prop changes -- essentially modelling your application as a "state machine" and eschewing the need for a "view model" or manual synchronization of DOM state to application state.
With the "rerender" function I fear any nontrivial application will devolve back into the tangled web of event listeners we left behind when moving to React.
Personally - I think a library like this is only useful for a very narrow audience: people with an affinity for JSX that are only building webpages (not web "apps") with some basic progressive enhancement features that can be kept track of pretty easily.
I don't mean to be overly negative here - I just suggest that you alter the documentation to be more clear about the differences/limitations when compared to react. The existing docs/example is almost (unintentionally, I'm sure) misleading in my opinion.
- spiffytech 6y agoI've been building some projects with Crank.js and Mithril, both of which require an explicit function call to rerender the application after changing state. In theory, that sounds terrible; I don't want to keep track of when my app needs to rerender, or worry about a stale DOM because I forgot to rerender after some event. In practice, it's a breath of fresh air compared to my work with React/Vue/Svelte. Everything is just so simple; I can use vanilla JS data structures and code organization patterns. I can architect my frontend state and logic in the way that makes the most sense for my domain, instead of ceding control flow to a heavy, footgun-y, limited-expressivity framework that demands to know everything my app does so it can decide on its own when to rerender. I'm tired of debugging confusing bugs because React hooks mix asynchronous control flow inside the render loop and my app has to have correct rendering and logic for every intermediate state of a chained sequence of useCallback/setState hooks. Tired of telling my team we have to put off a feature because it'll take a week to do something that feels like a 3-hour task because refactoring around a framework's control structures is harder than refactoring ordinary JS features. Tired of magic reactive compilers that create buggy renders and template languages that are only nice to work with if you use the One True Blessed VS Code Plugin, and tired of frameworks that need CLI scaffolding tools because they're more complicated than anyone wants to initialize with a blank editor. Crank.js, Mithril, and (at a preliminary glance) Forgo are very compelling to me. They offer the declarative, self-contained nature of components that I love from React/Vue/Svelte and the type safety of TypeScript for view code instead of template strings. My whole project scaffolding is just installing esbuild and generating a tsconfig.json. Maybe toss in browser-sync and watchexec if I'm feeling fancy. I don't need to make major architectural decisions based on the preferred state management tool, because these frameworks couldn't care less about how state is managed. And if I really want automatic rerenders, it's 10 LOC to write a reusable ES6 Proxy that returns an object I can dump state values into that will auto refresh if I reassign a property. And these frameworks still feel like a state machine in the same way React does - view code is declaratively rendered from application state. There is synchronization of state to DOM, but only in the sense that you have to explicitly invoke the declarative engine, and not in the sense that you have to manually synchronize like you would using jQuery to find and change DOM nodes. Keeping up with manual refreshes feels so simple and easy compared to all the hoops I've jumped though with the household name frameworks.
- daveidol 6y agoThanks for sharing your perspective. I happen to disagree with you on a lot of these things - but I guess I shouldn't be so dismissive about manually rerendering and assuming it won't scale to larger applications. Speaking to your specific examples: I do agree that some of the new React hooks (especially useEffect) seem to promote an ... idealistic idea of how your component should trigger and react to side effects (especially if you enable the eslint plugins) - namely always due to changes in reference equality. If you need to deal with other things (like an ID changing in a nested object that gets recreated on each render) it can be a big headache and error-prone. On the other hand - most of these hooks (and libraries and build tools you are alluding to) are easy to modify or use something else if you don't like them. Personally I find that much easier than building web apps like I used to pre-React and dealing with manual state synchronization. But to each their own! I've seen some pretty clean non-React codebases and I've seen some pretty messy React ones, just as I have on the flip side.
- no_wizard 6y agoSincere question, how many people work on this application or suite of applications? One, ten, twenty? It's as the number of developers grow on projects that these things become nightmares. Having worked somewhere that used React and had extremely strict eslint and typescript settings, it was all so uniform (those type checking static linting really keep the guard rails on code quality) because you were guided to use the same effective patterns in solving those problems. In fact, all the interesting work started happening outside interactions with the framework (and more around redux, in this case) so we were more focused on business logic and other concerns, react fell straight into the background. There were only ~25 developers or so. The ecosystem and the framework really lent itself hand in hand. That shouldn't be left out of discussions like this. I can see this model falling flat on its face after about 6 developers working in this system, especially since there is no adjacent tooling that specifically made to keep the guard rails on code quality. I'd love to hear a counter example to that. Edit: my point is, in order for something to be an acceptable alternative to React, it needs to have the ability to thrive in an example like I gave. React isn't for the 1 man shop, per se, or even perhaps a team of 5-6 developers that can coordinate well. Its real strength is in large application development, with `n` number of developers, where n is greater than 6. Thats just been my experience.
- lhorie 6y ago> With the "rerender" function I fear any nontrivial application will devolve back into the tangled web of event listeners we left behind when moving to React. Disclaimer: I'm the author of Mithril.js (A React-like framework that got mentioned in some other comments). I do think that the naive approach of eager render (a la backbone) can a bit limiting in terms of large scale applications, but I think the question of scalability is more nuanced than whether a rerender function exists. I don't think calling a function vs not calling a function is necessarily a meaningful distinction: React's own `setState` is a form of "rerender" function. The "devil in the details" comes from what the semantics of re-rendering are, and how that ties to the overall philosophy of the library. In React, `setState` abstracts over batching, meaning that one can, for example, call dozens of setState hooks from an event handler and not have to worry about multiple repaints. But on the other hand, if you're sharing state between, say a list view and a counter pill in different areas of an app, that involves a bunch of extra code (be it data-down, events-up, or using Context or redux or whatever) On the other side of the spectrum, too much implicitness isn't necessarily good either. Angular.js had some notoriously difficult to debug rendering loop issues when you used watching in certain ways alongside Angular.js' auto-render system. In Mithril.js, the default is that event handlers do not require explicitly calling a rerender function at all in the first place, because it starts from the assumption that 99% of the time you do want to rerender when an event occurs. But Mithril.js does also offer explicit bail-out-of-auto-render, as well as immediate rerender and batch rerender functions because in some rare cases you do want to control exactly when to render (e.g. you might want to actually double paint if part of your state is computed from bounding box measurements, or you might have multiple third party integrations in different areas of an app that render after another third party async computation completes, and ALL of that needs to be batch-rendered if they fall in the same event loop cycle). React's philosophy is very much to always think in terms of state snapshots, and the fact that its APIs are largely declarative reflect that. Mithril.js can also be used in a declarative fashion, but it's not as prescriptive. It also allows the developer to think in terms of timelines, and procedural APIs excel for that use case. Ultimately, though, good design comes down to being deliberate about what kind of semantics works well for what kind of mental model.
- ricardobeat 6y agoAs others have already pointed out, it's a bit of a misconception about React, certainly not helped by it's name - it is not truly reactive. Think about all the ways you can trigger a re-render: either `setState`, `forceUpdate`, dispatching an event, or some other kind of update function from a state management library. It doesn't react to any kind of assignment like would happen in Vue or Svelte. They do exactly the same as your `rerender` function here, it's just nicely hidden. There will be no more of a mess of event listeners than you'd get using React.
- daveidol 6y agoSure, it doesn't react to assignment, but it still encourages the immutable data patterns of a more functional/reactive programming style. The docs for Forgo here show a lot of direct DOM manipulation and/or direct assignment to mutable data structures, which you then have to synchronize. I personally almost never have to think about these things when I build with React and treat everything as immutable / pure. Then things update according to reference inequality / shallow diffing of props. You can even update a prop at the top of the component tree and it won't re-render children that didn't actually change (and without you having to orchestrate that yourself).
- ricardobeat 6y ago> you can even update a prop at the top of the component tree and it won't re-render children that didn't actually change That's true; the upside of immutability was supposed to be more efficiency when doing reconciliation. But in reality every large React app I've ever seen re-renders entire swaths of the component tree unnecessarily due to complexity - especially now with Context, nullifying that. It seems that a whole lot of people actually prefer mutability. See the popularity of MobX, and even libraries like seamless-immutable actually have the goal of offering a mutation interface that generates immutable objects underneath. If you can have mutations and correctness, sounds like a good deal. I've been using Svelte a lot recently, and it's a breathe of fresh air to not worry about component lifecycle. On top of that, React doesn't do inequality checks unless you explicitly use PureComponent, or wrap function components in memo(), so you need a lot of manual work to actually get that benefit. It's basically the inverse of having to call `rerender` everywhere.