Skip to content
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

Native supports a stable style prop reference with React.memo #3150

Closed

Conversation

philipbulley
Copy link

@philipbulley philipbulley commented May 20, 2020

This is a follow up to the closed #3020 (cc: @Federkun, @kitten) and I have raised the following new issue which provides a rationale for the proposed changes: #3149

In #3020, the consensus was that memoization of the resulting style prop would be too expensive to run on every instance when only a subset of use cases would benefit.

Update:
This PR initially explored this approach:

import { styledMemo } from 'styled-components/native';

But then after feedback, that was reverted and it now only employs a memoize optimisation for React.memo components.

Caveats

  • I haven't used flowtype before, so might need a hand with anything flow specific

@Federkun
Copy link

Hi @philipbulley, thanks for this PR!
My opinion is that a styledMemo, while allowing to support this use case, may still not be the best abstraction? It may leak to the client code the concept that a memoized component should be handled in a different way than normal. Usually using any kind of "decorator" should be transparent to the client code. If we have a styledMemo, removing the memoization and/or add it back in may require to change styledMemo with styled and vice versa as well.

To be honest, I'd like much more to relaying on the implementation details of React.memo, to detect if the component is memoized or not ( something along the line of ReactComponent.compare !== undefined ) and act accordingly. While still not ideal, at least it shield all this from the client

…or the resulting style prop; Remove styledMemo proposal
@philipbulley
Copy link
Author

@Federkun that's a good point and would be ideal, thanks!

ReactComponent.compare !== undefined is definitely a little obscure, especially as it relies on the fact that compare === null when no compare fn is passed.

An alternative (also not ideal) is to use introspection on the Element Type elementToBeRendered.

Expand for commentary on introspection woes...

1️⃣ This would be great, except that it doesn't work, as ReactIs.isMemo expects to be passed the return value of React.createElement:

ReactIs.typeOf(CustomComponent) === ReactIs.Memo
ReactIs.isMemo(CustomComponent) // sugar coated version of above

Several people have proposed a solution that can introspect an element type

but neither of these have landed.

2️⃣ This works 🤮 :

ReactIs.isMemo(React.createElement(CustomComponent)) // true

But I don't imagine it would be at all healthy for perf, especially as this would run for every custom component. Let's not go there!

3️⃣ Another option — if we don't mind looking at implementation details — is this approach: facebook/react/issues/12882#issuecomment-440227651
I'd argue that checking $$typeof is more or less as risky as ReactComponent.compare !== undefined, but is a little more explicit as to its intention.

See the usage of this technique in MobX:
https://github.com/mobxjs/mobx-react/blob/376bff72d84ae8d342c55d1fb25ff81a223624d2/src/observer.tsx#L14-L16

I've implemented the technique that MobX uses and it works a treat! I've added tests too. Please see the latest commit.

⚠️ Finally, the build will fail as I haven't sorted out the types for memoize-one — I don't know much about the FlowType ecosystem, what's the easiest acceptable course of action here? Write a custom definition?

@philipbulley
Copy link
Author

Can anyone who better understands Flow help with this issue please?

Why does this happen?

$ flow check
Error ┈┈┈┈┈ packages/styled-components/src/models/StyledNativeComponent.js:4:24

Cannot resolve module memoize-one.

     1│ // @flow
     2│ import React, { createElement, Component } from 'react';
     3│ import hoist from 'hoist-non-react-statics';
     4│ import memoizeOne from 'memoize-one';
     5│ import isEqual from 'react-fast-compare';
     6│ import merge from '../utils/mixinDeep';
     7│ import determineTheme from '../utils/determineTheme';

Despite memoize-one having flow types.

@philipbulley philipbulley changed the title WIP: Export styledMemo from /native supporting a stable style prop reference Native supports a stable style prop reference with React.memo May 22, 2020
@kitten
Copy link
Member

kitten commented Aug 9, 2021

Closing due to inacitivity. I think we could consider changing the approach of dynamic styling in the implementation if we do split off the package to avoid complexity / differences in the CSS pipeline to the main package, see #1617

@kitten kitten closed this Aug 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants