-
Notifications
You must be signed in to change notification settings - Fork 67
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
"Code review" #38
Comments
Hey @Merri! This is one of the most valuable issues I’ve received on Github thus far. Thank you for doing such a thorough code review, it's great! There're very good points, so let me say first off that I agree with the majority of them. I'd like to include these changes – probably with the exception of terminology for obvious reasons – but I want to start with leveraging code size reduction and better organization and inlining of code. Ideally we’d implement enough of your suggestions, so that react-lazy can include this package as one of its dependencies. If you think this is possible, I’d like for either you or us to open a PR soon, so that we can release a new version containing all the changes. So let’s break down your suggestion into actionable points – let me know later if I left anything out: IntersectionObserverContainer.jsI measured the uglified Babel output (after removing the runtime assuming it’s in a shared module) and yours comes out almost 200 bytes lighter 👍 Observer callbackDo not see the part of the future bug, but it should be moved to the above-mentioned file indeed 👍 Abstraction
New object in reduceYep, I didn’t see that one 👍 WarningI also thought it’d be removed soon, but later I decided it might stay a while, since probably too many people have relied on onlyOnce on their codebases at this point. So let’s IF for NODE_ENV too 👍 TargettingThe problem with PureComponentUnfortunately, PureComponent can’t compare children efficiently like I was saying. It's not the react-way to optimise things, to store a reference either. We won’t be able to determine if we need to re-observe a DOM node unless we re-render, because that node reference is inside the ref callback, so that's what we do. Instead, when we use You can apply I’m extending myself quite long here, but the point is that you probably shouldn’t be re-using the observer for different target types, and if you do, we expect the correct behavior to happen. SemicolonsI don’t care. I really don’t care, let’s remove them, let’s add them… Post-processing will get rid off most of them anyways. TerminologyI am pretty sure you can keep |
Great :) I guess one way to go would be to create a pull request with a lot of micro size commits, then let you decide which ones of the changes you want to take and leave out the commits that don't make the cut (since there are some less important changes/suggestions). Then once there is a new version out I'll update react-lazy and add this package to the peerDependencies. Sounds like a plan? Or would you rather want pull requests that each have a specific theme? CallbackThe bug with callback is that if it was possible to actually change the callback then it would be become possible that an incorrect instance of IntersectionObserver would be given for options that match existing IntersectionObserver, but have a different callback, since there is no check against it. This is why I think callback shouldn't be passed to the create method as the code assumes it to always be the same. isDOMTypeElementTo me testing this is testing a React feature and it shouldn't be a test concern for this component. This method would only break if React changed a lot, in which case they are probably responsible enough to create a new method instead of breaking an old one. TargetThis one (and PureComponent) were the things I were least sure of suggesting as I didn't go ahead and write any code. There is something that bothers me with using three variables for what essentially should need only two variables (past and present). Also, the fact there is mutative code in render method makes me think there would be something wrong. If I understand the cycle correctly off the top of my head, it goes render -> handleNode -> componentDidUpdate. If this holds true then But this is again where I assume a lot without testing whether my understanding is correct :) |
Sounds like a plan. Looking forward to it 🎉
That's right, we need to stop observing it before the node is removed from the DOM. This part was thought out way before methods like I think it might be enough to just modify cDU like so: componentDidUpdate(prevProps) {
if (this.targetChanged) {
if (!this.props.disabled) {
this.observe();
}
} else if (this.compareObserverProps(prevProps)) {
this.unobserve();
this.observer();
}
} Thoughts? |
Hmmh, I guess that forces the boolean variable. Doesn't seem worthwhile to change the code to be "proper" and make I try to fork and start throwing commits together during the weekend. Had to wake up earlier than usual which isn't ideal for getting anything done. |
Hullo!
This isn't a real issue; instead I thought I'd drop a line since I used this project's code as a basis when implementing Intersection Observer into an older existing lib where I didn't want to have some of the baggage that this project currently has (or had), and I also wanted to do some minor changes to terminology that this project most likely doesn't want to include.
I think this project's implementation of Intersection Observer API for React is the best on npm, and I also think this project is now very close to version 1.0.0 as the Symbol issue was just removed. The weaknesses, from my point of view as an author who might want to use this project in their lib, are mostly in dependencies and use of modern code syntax that results into verbose results (as long as we need to keep babelizing and polyfilling).
I think it is ideal for any component that is used as a basis for other components to have as little dependency and as little unnecessary abstraction as possible. So, from this perspective here are some things that I changed when I refactored this project as part of react-lazy.
IntersectionObserverContainer.js
This goes a lot into opionated side of things, but I couldn't see any purpose for making IntersectionObserverContainer a class. Essentially all the methods are static functions and nothing is self-contained into the class itself. Thus I changed the file into intersectionObserver.js, removed class and renamed the functions to be a bit more verbose.
The advantage in this is reduced final code size. And there is also a little bit less confusion as well since IntersectionObserverContainer is not a React component, which one might first assume it to be.
The callback method
I had two thoughts related to the callback:
new IntersectionObserver
.The first point introduces a possible future bug as callback is not checked against. Of course the current implementation always has the same callback, but the interface gives an impression that one could change it.
For the second point I think the callback method becomes easier to understand when it is moved to the other file as all the related Map and Set context is there.
Abstraction
Doing these changes would reduce code size.
Unnecessary creation of new object in reduce
In component's
get options
is an unnecessary object spread: you can freely mutate an object you have created for a reducer.warning is included for production build
I guess this should be inside a `process.env.NODE_ENV !== 'production' block. In the other hand onlyOnce is about to be removed so worth fixing only if it will take a while for the next major release.
Targetting
this.target, this.renderedTarget, this.targetChanged... I know these are very fast to access if compared to calling this.setState, but I can't really avoid the thought that the code could be simpler with setState.
PureComponent?
Current target management prevents using this. With setState this would become a viable solution to the shallow props checking. Of course it isn't exactly the same: the
shouldComponentUpdate
implementation doesn't check the contents of an array, only the reference. Maybe threshold could be a string instead of an array to make things easier?Final thoughts
For reference, here are links to how I refactored those files:
I did other minor changes as well which might be interesting to see, but there are so many changes (and I don't use semicolons) that diff isn't much of help. Most of the code should seem very familiar as it does implement the exact same logic, but only does it with either slightly faster means or code that results in reduced babelized code size or less dependencies.
And then there is also the addition of viewport (root) and cushion (rootMargin) props, which seem like easier to understand what those props do than what IntersectionObserver options say.
Anyway, hopefully these thoughts are of some value :)
The text was updated successfully, but these errors were encountered: