-
-
Notifications
You must be signed in to change notification settings - Fork 167
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
Bug: All props are reapplied if any prop changes #428
Comments
Hey @RJWadley, I'm not one of the authors of this library so take what I have to say with a grain of salt but what you're experiencing is, in my eyes, the expected behavior. React provides us with a hook for this specific case: useCallback.
When you use an inline function as a react prop, that's technically a different reference to a function each time the component re-renders which would cause the Sprite component to re-render. |
Hi @maximtwo, thanks for your response! Standard react behavior is to only apply props if they've changed. This behavior is intentional and is one of the things that makes react fast. I've tweaked the example I provided earlier to run in standard react. If this were the expected behavior we would see the box flickering between red and green (I'm changing className instead of alpha). The callback solution you've provided actually works great for simple solutions, but can't save us every time. Imagine, for example, a simple box that fades in, then moves around the screen randomly. When I click the box, I want the camera to center on the box. Here's what that callback would look like:
But wait, this isn't working at all... Oh, that's right, we're missing some dependencies from our callback! I'll just add those in:
You've probably figured out why this doesn't work now. If x and y are changing every render, now this callback is too. This means all of our props get reset every time x and y change, including the alpha from that fancy fade-in I mentioned earlier. But also, it's not just callbacks! Anything else can cause this too, including objects and regular variables. |
I think I'm just flat out wrong about the way react treats functions passed inline via props and great example proving me wrong there. The empty dependencies array passed to useCallback was not an oversight btw ;) but I see what you mean now about how the props are being reapplied on subsequent renders and I'll bow out of that conversation. One thing I'll add though is that you might be going against the grain here by changing things via refs instead of just props. For something like this I would use (heh) useState to store the alpha (or any other prop) of the sprite and modify that instead of touching the ref directly. Changing props in that way is not slow if that's what you're thinking. |
I can confirm this is indeed a bug and was one of the reasons I decided to base a rewrite of I amended the provided example to show that the bug is not happening when using Since we decided |
@maximtwo @RJWadley - I believe you're both right (sort of). @maximtwo what you're describing is exactly how React works in user-land: A render will always happen on any prop change, unless you're specifically preventing it via a custom props comparison function in @RJWadley your example is exactly how I would expect it to behave, but I agree that the vanilla React version does work, albeit I would suggest by accident rather than design. Currently https://github.com/pixijs/pixi-react/blob/master/packages/react/src/utils/props.js#L178-L207 Your vanilla React version works because when the Going forward the "fix" would seem to be to avoid applying props unless they've changed, I don't know if this might have any other repercussions though. |
@baseten for sanity reasons I think it would make the most sense if react-pixi behave similarly to react-dom as it would make working with both PIXI and DOM more predictable.
The actual origin of this logic you can find in the original react-pixi package (for React before fiber was a thing), see: When I wrote the first fiber reconciler I was going for maximum compatibility, so I wouldn't have to do a complete rewrite of our applications using react-pixi when switching to react-pixi-fiber. At that point I didn't really try to understand decisions made in the original react-pixi, I was merely trying to make my applications work in React 16. Later we discovered many issues with updating the scene tree, so I decided to look at what react-dom was doing and rewrite react-pixi-fiber to do it the same way, hence the changes introduced here: The change meant that only props that changed were applied. If you have look at the example sandbox I linked in my comment above you'll see that the behavior is comparable to react-dom example provided by @RJWadley. |
Current Behavior
When one prop changes, it seems that all the props are re-applied, rather than only applying the changed props.
This is most noticeable when an object has event handlers since functions are passed by reference and 'change' on every render. This means any element with event listeners gets all its props reapplied on every render, which is bad news if you're doing any sort of animations in an effect.
Expected Behavior
When a prop changes, only that prop should apply.
Steps to Reproduce
I've made a simple reproduction here. In this example, the initial alpha of 0.1 is incorrectly re-applied on every render because of the event handler. This causes the sprite to switch between the initial value (0.1) and the value applied in the effect (1.0) endlessly. Comment out the onclick property to see the expected behavior.
Environment
@pixi/react
version: 7.0.3pixi.js
version: 7.2.1React
version: 18.2.0ReactDOM
version: 18.2.0Possible Solution
No response
Additional Information
No response
The text was updated successfully, but these errors were encountered: