-
Notifications
You must be signed in to change notification settings - Fork 75
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
Feedback after creating a simple app #170
Comments
The app is great! I’ve been following the file system access standard closely so it’s exciting to see an app which uses it! My thoughts: Defining I’m not 100% on why the Table component needs to have async render props. Personally, I would probably have a single async function which turns an array of FileSystemHandle objects into the data structure you want for the table. This approach would be framework agnostic. I typically try to avoid render/callback props whenever I can. Maybe you have good reasons for implementing things your way. As far as the Second, the other file/directory provisions all seem related, and when consumed, you seem to consume multiple of these provisions at once. Therefore, I recommend putting these 4 provisions into a single object, or maybe a helper class. Finally,
Yes, this is going to be a problem for Crank (see the discussion in #37). I can’t guarantee that components failing to update is because of user error and not a bug in Crank itself, and I must admit that I also often fail to remember to refresh components, but I still believe explicit, opt-in refreshing is the best approach. I have a blog post in the works about why I think this is the case, but for now know that it is an intentional decision of the framework to under-render, as opposed to over-render, because it makes the executions of your components clearer, it helps avoid pathological performance problems when applications reach a certain size, and because it allows for advanced rendering patterns (like having a single parent rerender every child component rather than child components rerendering themselves whenever they detect a change). If you have specific situation which you’re trying to debug, I’m happy to help, given that your code is in the open! All in all, thanks for trying out Crank and sharing your thoughts! Means a lot 🥰 |
Glad that you like it :). I've been following this standard as well. It opens new possibilities for web dev :)
So maybe it could be one of a good practices mentioned in docs?
Yes actually, I wouldn't do it again with async component if I had current knowledge. I will probably change it into regular component. But as you suspect, there was a reason why I decided to use async. I thought like: "Ok, I have async components let's go a little bit crazy and use its full potential" :). So at the beginning I wanted to display table structure and load individual cell values asynchronously (displaying "Loading..." in the cell while waiting). Modification date, size and type are all promises so I thought that it would be nice to display something right away instead of waiting for the data to load. You know rendering initial content to the user sooner, so overall app would feel more responsive. But then, I had to implement sorting and I was like "Oh ok, I have to load async data first to do sorting", so yeah that wasn't the best approach.
Yep good point, I will split it. However, I don't know if I follow what you mean by saying "custom css properties". I'm already using css variables and
Hmmm right good point. I haven't thought about it. I will try that.
Oh I had to miss that when reading docs. Good to know. I will probably first experiment with some other state management options. But I will keep it in mind when a good use case will emerge.
Yep probably it was my error but I agree that explicit refresh is much better and cleaner. For instance, after spending most of my life programming using classes, I've recently switched (at least for some things) to functional programming and when used correctly (like pure functions) my code became so much nicer and easier to understand. And I see similar problem with refreshes in React. Sometimes, you have to deeply understand how React works under the hood to write most performant and bug-free code. I think React team made a mistake of going with synchronous approach (because it's easier to understand) while hiding a lot of logic from the user. Just by reading component's code from the top to bottom I don't really see how things will work/render. Even recently (I'm working with React for several years already) I had to debug my code line by line and do console.logs because I was frustrated that it didn't rerender in a way I wanted. Your approach with explicit refreshes is just more aligned with the functional way of thinking. If you see
Can't wait to read it :)
Thanks! :) I work on this app over weekends and if I hit a wall then I will definitely ask for help :).
No problem! :) I will definitely share more thought as I spend more time with it. Thanks again for the great library! |
Yep I agree and will try to add it to the docs soon.
Ah I misunderstood the code. I assumed you were implementing all of the color scheme stuff in JS space. Maybe you could use
Yeah the sorting requirement will probably require you to wait for the entire table data anyways, but for this use-case I hope to eventually get to the point where we can coordinate components the way SuspenseList works for React by deferring the mount of certain child elements based on some API. Async mounting and unmounting of nodes is coming soon, I just need to book some time to work on it.
Yes this is basically what I’m addressing with my draft blog post. Essentially, I’m asking why do we need data binding or reactive solutions, given that the evidence from the past five or so years suggests that most apps are pathologically over-rendered and over-executed. Crank has the unique problem of choosing to under-render rather than over-render, and this usually manifests as the UI failing to update, but I think this is a good problem insofar as it is immediately obvious and teaches you about the actual execution of your application. I can see how people would call it “a step backwards” but I think it’s necessary. It’s tough because the true value of explicit rendering isn’t immediately obvious until you’ve spent years debugging reactive systems and tweaking them to render less for performance reasons. |
Closing for housekeeping purposes! Thanks for the feedback! |
Hey, I've created a simple app for renaming image files using Crank.js that you can checkout here https://files.jagi.io/ and the source code is here https://github.com/jagi/files
And here is a little bit of feedback that I have after spending some time with it. It's still very, very simple app, so I will probably have more to say when I start adding more features like dialog windows, forms etc. But still I already have some feedback.
GOOD:
Promise.all
is the way to go but I just had to switch my thinking from sync to async components. So it's just a problem of someone coming from React environment. https://github.com/jagi/files/blob/main/src/components/table.tsx#L108-L120this.addEventListener
to handle events is great. Again, just because I'm coming from React, I had to change my habits. I remember, that once I wanted to handle two events from two elements in one component and I didn't like switches/ifs in the event handler but then I've just split it into two smaller components. So I think it's good to think aboutthis.addEventListener
as the handler for the top level element in the component. So far, I haven't had problem with this approach.BAD:
this.provide
to expose them to children https://github.com/jagi/files/blob/main/src/components/state.tsx#L57-L61. Also in some cases, having to update both of them when plain value changes https://github.com/jagi/files/blob/main/src/components/state.tsx#L64-L65 although not having to do it when working with references https://github.com/jagi/files/blob/main/src/components/state.tsx#L75. I will probably end up rewriting this part to use something like Zustand and creating Crank wrapper or just creating my own app state management library for Crank. I don't have problems with local component state but app state management is far from perfect.dispatchEvent
calls:So I ended up creating classes for each event type like this:
and then using it is much cleaner:
So actually that one I kinda solved by myself and I'm happy with it. But just saying that I (and probably most people) like the idea of writing less code :) especially when you used some other state management library.
Sometimes I also had issue with components not refreshing but maybe that was just my bug in the code. I have to investigate it more and confirm. Sometimes it would be good to batch
this.refresh
calls.I know that this feedback is nothing mind blowing and you probably are aware of all of this, but just wanted to share my experience.
The text was updated successfully, but these errors were encountered: