jasonkillian | 3 years ago | on: A Visual Guide to React's useEffect (2021)
jasonkillian's comments
jasonkillian | 3 years ago | on: Why React Re-Renders
It _is_ true that when you call a React function component it "runs its code" just like any regular old JS function. But when that function gets run and what all the side effects of its code are actually is quite complex.
jasonkillian | 3 years ago | on: Extreme explorations of TypeScript's type system
I think this is the key. If treated as you describe, meaning the advanced types are well-written, well-documented, and well unit-tested as if they are "true" code, then using them shouldn't be too much of an issue.
However, I think people often just assume that the types aren't "real" code and thus the normal concepts of good software engineering don't apply and type monstrosities which nobody can understand result.
Imagine if this code[0] wasn't well-documented, fairly clearly written, and also tested. It would definitely be a liability in a codebase.
In addition, the rules of how advanced TypeScript concepts work can be quite nuanced and not always extremely well defined, so you can end up in situations where nobody even _really_ understands why some crazy type works.
[0]: https://github.com/sindresorhus/type-fest/blob/2f418dbbb6182...
jasonkillian | 4 years ago | on: Modeling chopping onions: The importance of mise en place
Wanted to take a second to address your comment about performance, lqet. All your points are absolutely fair - I personally apologize for some of those layers of divs and some of that JS as they're definitely my fault!
For context, Hex lets you write Python and SQL code in a notebook-esque format and then create apps from that to share across the web. So there's actually quite a breadth of functionality we need to support under the hood that adds to frontend complexity. We also revamped our whole app-building experience recently, so there's a couple straggling bugs (like the text selection one you mentioned, whoops!).
But I totally agree with you - thinking about all that JS makes me wince a little haha as we definitely care and want to improve frontend performance. We plan to make better use of code-splitting and lazy-loading of JS so that the frontend code for more complex apps is only pulled in if/when necessary. (We also want to work on building better tooling to make analysis of code-splitting effectiveness easier - we've found that a lot of existing webpack bundle analyzer tools don't provide enough visibility for our use cases. Maybe an open source project for us one day!) And we want to decrease over-the-wire data size and reduce necessary network calls so you can get a faster initial load. We're a small team, so can't make promises when exactly this will all happen, but hopefully with these changes and other improvements things will feel a bit snappier someday soon
jasonkillian | 4 years ago | on: Flatten Arrays in Vanilla JavaScript with Flat() and FlatMap()
In TypeScript, you might have an array of multiple types (e.g. `Array<A | B>`), and use a `filter` call to only keep the `A`s. However, in many situations TypeScript can't figure this out and the resulting array type is still `Array<A | B>`. However, when you just use `flatMap` to do nothing more than filtering in the same way, TypeScript can determine that the resulting type is just `Array<A>`. It's a bit unfortunate really - `filter` is faster and more readable, but the ergonomics of `flatMap` type-wise are so much nicer! Just some interesting trivia.
[0]: https://github.com/microsoft/TypeScript/issues/16069#issueco...
jasonkillian | 4 years ago | on: Flatten Arrays in Vanilla JavaScript with Flat() and FlatMap()
jasonkillian | 4 years ago | on: We memo all the things (2020)
The main downsides are that they take slightly longer to type and slightly decrease the succinctness of the code. And then there are a few React-specific complexities they add (maintaining the deps arrays and being sure not to use them conditionally) but these should be checked by lint rules to relieve developer cognitive load.
Of course I'd rather not have these downsides, but in the end, it's still much less developer overhead than having to constantly profile a large application to try and figure out the trouble spots and correctly test and fix them post-hoc. And it means users are much more likely to get an application that feels snappier, doesn't drain as much battery, and just provides a more pleasant experience overall, which is worth it imo.
jasonkillian | 4 years ago | on: We memo all the things (2020)
The argument that a lot of popular React voices have made, "React is fast and it's prematurely optimizing to worry about memoizing things until a profile shows you need it", has never rung true with me. First and foremost, there's a huge time cost to figuring out what those exact spots that need optimization are, and there's also an educational cost with teaching less experienced engineers how to correctly identify and reason about those locations.
There are only two reasonable arguments for not using `memo`, `useMemo`, and `useCallback`. The first is that it decreases devx and makes the code less readable. This one is true, but it's a very small cost to pay and clearly not the most important thing at stake as it's only a slight net effect. The second argument is that the runtime cost of using these constructs is too high. As far as I can tell, nobody has ever done a profile showing that the runtime cost is significant at all, and the burden of proof lies with those claiming the runtime overhead is significant because it doesn't appear that it is typically when profiling an app.
So, given that the two possible reasons for avoiding `memo`, `useMemo`, and `useCallback` are not convincing, and the possible downsides for not using them are fairly large, I find it best to recommend to engineering teams to just use them consistently everywhere by default.
jasonkillian | 5 years ago | on: Dates and Times in JavaScript – A New API for Dates from TC39
Figuring out a name is still part of the ongoing discussion, so this specific case of `LocalDateTime` isn't a huge deal, and I might have misrepresented things slightly in my original comment, sorry! But I do think the overall point still stands - that it might be best to just use the same names and terminology as Java does.
jasonkillian | 5 years ago | on: Dates and Times in JavaScript – A New API for Dates from TC39
Is it too Java-y that it wouldn't make sense to port to JS? Are there copyright implications?
The JS Temporal proposal _does_ as far as I can tell, share many of the underlying fundamental concepts, which is great, but then confusingly has some types, such as `LocalDateTime`, which mean the exact opposite of what they do in the well-known Java API [3].
There is still discussion going on about these details, but from my perspective it seems like the best thing would be to just copy the Java naming conventions exactly.
[0]: https://www.joda.org/joda-time/
[1]: https://docs.oracle.com/javase/8/docs/api/java/time/package-...
jasonkillian | 5 years ago | on: A Critique of React Hooks
The rules do start to get really tricky though with complex use cases of `useEffect` and multiple levels of nested hooks, and implementation problems are often not easy to spot or debug.
Dan Abramov has written a lot about the philosophy of hooks[0] at his site overreacted[1], I'd love to see a 'retrospective' write-up from him or another React team member about what they think the success and failures of hooks have been so far and if there are any changes planned for the future!
[0]: https://overreacted.io/why-isnt-x-a-hook/, https://overreacted.io/algebraic-effects-for-the-rest-of-us/, https://overreacted.io/a-complete-guide-to-useeffect/
jasonkillian | 6 years ago | on: Fixing JavaScript's Date (2017)
jasonkillian | 6 years ago | on: Fixing JavaScript's Date (2017)
https://github.com/tc39/proposal-temporal
At a glance, it does follow the same ideas as the great Joda Time library (now a part of the Java standard library), and there's currently a port of this library for JS which is quite nice:
jasonkillian | 7 years ago | on: New GitHub Feature: Subscriptions View
jasonkillian | 7 years ago | on: Show HN: We Got Sick of Giving Out 'Ballpark Estimates' So We Built This
Either plagiarism was involved, or there's some underlying library that's the same for both, or they both hired the same company to build their MVP ;)
HowMuchToMakeAnApp is by "Commite, a digital studio specialized in driving ideas from inception to launch" based out of "Seville, San Francisco & New York".
BuildMyMVP is made by "ProductDone a digital studio based in Auckland, New Zealand".
The two sites side by side: https://imgur.com/a/e7OVYVa
jasonkillian | 7 years ago | on: 38% of bugs at Airbnb could have been prevented by using types
Why is that? There were dynamically-typed backend languages long before Node.js became popular. And you now can easily have a TypeScript-based Node.js backend, which gives you the nice benefit of having the exact same language and types for both your backend and frontend. I'm not saying the Node runtime is perfect, but I don't understand why having a runtime that lets you use JS/TS as a backend or local language is quite such a bad thing.
jasonkillian | 7 years ago | on: Spotify will now suspend or terminate accounts it finds are using ad blockers
[0]: https://community.spotify.com/t5/Android/COMPLETE-GUIDE-How-...
jasonkillian | 7 years ago | on: Making SetInterval Declarative with React Hooks
I'm having a little trouble explaining the difference well, I think this jsfiddle illustrates the incorrect case the article is talking about representatively: https://jsfiddle.net/7fLnvz5c/
jasonkillian | 7 years ago | on: Making SetInterval Declarative with React Hooks
In addition to the paradigm-mixing the article illustrates, I wonder if the actual hook APIs make things more confusing than necessary at some points. For example, in the `useEffect` hook API:
* the first argument is a function that on every render
* the return value of the first argument is a "cleanup" function which runs when the component is unmounted or before the effect is run again
* the third argument is an array of parameters which controls when the effect is run. If passed an empty array, the effect is only run at mount and cleaned up at unmount.
All the above means that the API is very implicit and doesn't self-document its intent all that well. An example, from the article:
useEffect(() => {
function tick() {
savedCallback.current();
}
let id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []);
I'm sure with more use these hook patterns will become more familiar. But it's clearly a lot harder to learn and understand than the original simplicity that helped propel React to popularity.Dan's arguments that hooks provide for easier abstraction and more composability is interesting to me though - if hooks are going to be "worth it" in the long run, I suspect this is why.
jasonkillian | 7 years ago | on: TypeScript Tricks: Type Guards
However, if you have control over the data shape, in general, it's nicer to take advantage of discriminated unions as you'll get more automatic typesafe compiler support. If you're not familiar with the construct in TypeScript, the docs give a nice example of them[0].
[0]: https://www.typescriptlang.org/docs/handbook/advanced-types....
I've had similar conversations many times with coworkers before when they were using `useEffect` to keep a state value in sync with a prop. The officially-recommended alternative of manually storing and updating an extra piece of state containing the previous prop value is cumbersome and also had ways it can go wrong. So, since `useEffect` works well enough in most cases and is easier, often the code just sticks with that method. I'm not entirely sure what's really best all tradeoffs considered, but it definitely illustrates how rough edges often pop up in hook-based React.