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

Intelligently SSR Responsive Children of Responsive Parents #132

Closed
rajington opened this issue May 14, 2020 · 7 comments
Closed

Intelligently SSR Responsive Children of Responsive Parents #132

rajington opened this issue May 14, 2020 · 7 comments
Labels
help wanted Extra attention is needed released

Comments

@rajington
Copy link

rajington commented May 14, 2020

tweaking the basic example

const { MediaContextProvider, Media } = createMedia({
  breakpoints: {
    sm: 0,
    md: 768,
  },
})

const App = () => (
  <MediaContextProvider>
    <Media at="sm">
      <Child />
    </Media>
    <Media at="md">
      <Child />
    </Media>
  </MediaContextProvider>
)

const Child  = () => (
  <>
    <Media at="sm">
      foo
    </Media>
    <Media at="md">
      bar
    </Media>
  </>
)

it actually renders foo twice and bar twice:

<div class="fresnel-container fresnel-at-sm">
  <div class="fresnel-container fresnel-at-sm">foo</div>
  <div class="fresnel-container fresnel-at-md">bar</div>
</div>
<div class="fresnel-container fresnel-at-md">
  <div class="fresnel-container fresnel-at-sm">foo</div>
  <div class="fresnel-container fresnel-at-md">bar</div>
</div>

but wouldn't it be possible to know that the second foo would never be visible?

this multiplicative growth could even make some trees larger than simply rendering the entire tree for each breakpoint on the server (also allowing the benefit that lower components can use the current breakpoint as a prop rather than wrapping everything in fresnel).

@damassi
Copy link
Member

damassi commented May 14, 2020

Hi @rajington - we discuss this in the pros and cons section of the readme, as well as in our blogpost. In short:

  • We can't know ahead of time what breakpoint will be matched, because a server doesn't have a display, and thus can't utilize matchMedia -- so we send down all breakpoints
  • However, on client mount, we can detect which breakpoint the client is matched at and we then clean up the dom
  • While this will get you pretty far and solves the problem of truely responsive SSR rendering, if you need to narrow things further can use @artsy/detect-responsive-traits. This is as close to an intelligent SSR pass as is possible, due to the nature of the constraints.

@rajington
Copy link
Author

rajington commented May 14, 2020

Thanks for the quick response (and this awesome library!). Apologies if I'm not understanding the README correctly or explaining my thoughts correctly. I really appreciate the approach this library takes to SSR by shipping both, this top-level one makes sense:

<div class="fresnel-container fresnel-at-sm">SM</div>
<div class="fresnel-container fresnel-at-md">MD</div>

but could we leverage context so that instead of:

<div class="fresnel-container fresnel-at-sm">
  <div class="fresnel-container fresnel-at-sm">foo</div>
  <div class="fresnel-container fresnel-at-md">bar</div>
</div>
<div class="fresnel-container fresnel-at-md">
  <div class="fresnel-container fresnel-at-sm">foo</div>
  <div class="fresnel-container fresnel-at-md">bar</div>
</div>

it renders

<div class="fresnel-container fresnel-at-sm">
  <div class="fresnel-container fresnel-at-sm">foo</div>
</div>
<div class="fresnel-container fresnel-at-md">
  <div class="fresnel-container fresnel-at-md">bar</div>
</div>

instead?

assuming this is the react tree from the first example:

  <MediaContextProvider>
    <Media at="sm">
      <Media at="sm">
        foo
      </Media>
      <Media at="md">
        bar
      </Media>
    </Media>
    <Media at="md">
      <Media at="sm">
        foo
      </Media>
      <Media at="md">
        bar
      </Media>
    </Media>
  </MediaContextProvider>

it'd be interesting if each Media not only rendered its children at certain breakpoints, but set a Context so that nested Medias could leverage it to see what breakpoints are valid, even on the server. Note that it's not trying to look at the client, but rather the branch of the tree that has already been limited to certain breakpoints.

It almost seems like what onlyMatch is for, but would want it multiple depths in the tree rather than just wrapping the App.

const Media = props => (
  // get all the breakpoints this component COULD render at from Context
  const parentBreakpoints = useContext(...

  // get all the breakpoints this component is asked to render at from props
  const myBreakpoints = 

  const intersection = ...

  if (intersection.length) {
    return (
      {/* passes down the potential breakpoints to any further nested `Media`s */}
      <Provider value={intersection)>
        ..
      </Provider>
    );
  }
)

something like that? i could try something in a codesandbox as well

@damassi
Copy link
Member

damassi commented May 19, 2020

This makes sense! If you have time would happily evaluate a PR, but agree this is a great suggestion.

@alloy
Copy link
Collaborator

alloy commented May 28, 2020

Nice, great suggestion 👌

@artsyit
Copy link
Contributor

artsyit commented Oct 26, 2020

🚀 Issue was released in v1.3.0 🚀

@rajington
Copy link
Author

Sorry I didn't submit PR but thanks for implementing @damassi!

@alloy
Copy link
Collaborator

alloy commented Oct 27, 2020

It was implemented by @kirkness, but thanks to the both of you for the collaboration that led to this! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed released
Projects
None yet
Development

No branches or pull requests

5 participants