• Stars
    star
    724
  • Rank 60,539 (Top 2 %)
  • Language
    JavaScript
  • Created about 7 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

โ†”๏ธ Hoc to easily map window sizes to props.

react-sizes

npm npm GitHub issues GitHub stars Twitter

Install

yarn add react-sizes
npm install react-sizes

What and why

React Sizes is a higher-order component with strong performance that transforms window sizes (width and height) into props.
You can check inside your component, for example, if user's window is less than 480 pixels of width, and add a custom content.

It can be very powerful for when you need to display different content for mobile and desktop. But it's not limited to this case. Just use that at your needs.

Usage

With class component.

import React, { Component } from 'react'
import withSizes from 'react-sizes'

class MyComponent extends Component {
  render() {
    return <div>{this.props.isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
  }
}

const mapSizesToProps = ({ width }) => ({
  isMobile: width < 480,
})

export default withSizes(mapSizesToProps)(MyComponent)

You can play with this example here.

As decorator.

import React from 'react'
import withSizes from 'react-sizes'

@withSizes(({ width }) => ({ isMobile: width < 480 }))
class MyComponent extends Component {
  render() {
    return <div>{this.props.isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
  }
}

export default MyComponent

Interoperate with other libraries.

import React from 'react'
import withSizes from 'react-sizes'
import { withState, compose } from 'recompose'

const enhancer = compose(
  withState('counter', 'setCounter', 0),
  withSizes(({ width }) => ({ isMobile: width < 480 }))
)

const MyComponent = enhancer(({ isMobile, counter, setCounter }) => (
  <div>
    <div>
      Count: {counter}{' '}
      <button onClick={() => setCounter(n => n + 1)}>Increment</button>
    </div>
    <div>{isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
  </div>
))

export default MyComponent

With functional component.

import React from 'react'
import withSizes from 'react-sizes'

const MyComponent = ({ isMobile }) => (
  <div>{isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
)

const mapSizesToProps = ({ width }) => ({
  isMobile: width < 480,
})

export default withSizes(mapSizesToProps)(MyComponent)

Mess with props.

(Added in 0.1.0)

import React from 'react'
import withSizes from 'react-sizes'

const MyComponent = ({ isMobile }) => (
  <div>{isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
)

const mapSizesToProps = ({ width }, { mobileBreakpoint }) => ({
  isMobile: width < mobileBreakpoint,
})

export default withSizes(mapSizesToProps)(MyComponent)

then:

<MyComponent mobileBreakpoint={480} />
<MyComponent mobileBreakpoint={400} />
<MyComponent mobileBreakpoint={600} />

With presets selectors.

- const mapSizesToProps = ({ width }) => ({
-   isMobile: width < 480,
- });

+ const mapSizesToProps = sizes => ({
+  isMobile: withSizes.isMobile(sizes),
+ });

Presets Selectors

You can check all our presets selectors at our main code src/withSizes.js.

withSizes.isMobile = ({ width }) => width < 480
withSizes.isTablet = ({ width }) => width >= 480 && width < 1024
withSizes.isDesktop = ({ width }) => width >= 1024

withSizes.isGtMobile = sizes => !withSizes.isMobile(sizes)
withSizes.isGtTablet = sizes => withSizes.isDesktop(sizes)

withSizes.isStTablet = sizes => withSizes.isMobile(sizes)
withSizes.isStDesktop = sizes => !withSizes.isStDesktop(sizes)

withSizes.isTabletAndGreater = sizes => !withSizes.isMobile(sizes)
withSizes.isTabletAndSmaller = sizes => !withSizes.isStDesktop(sizes)

If it don't fit to your needs, you can create your own selectors.

// utils/sizes/selectors.js
export const isntDesktop = ({ width }) => width < 1024
export const backgroundColor = ({ width }) => (width < 480 ? 'red' : 'green')

// your component
import { isntDesktop, backgroundColor } from 'utils/sizes/selectors'

const mapSizesToProps = sizes => ({
  canDisplayMobileFeature: isntDesktop(sizes),
  backgroundColor: backgroundColor(sizes),
})

sizes argument is an object with width and height properties and represents DOM window width and height.

Guide

mapSizesToProps(sizes)

sizes argument is an object with width and height of DOM window.

const mapSizesToProps = sizes => {
  console.log(sizes) // { width: 1200, height: 720 } (example)
}

In pratice, it is a callback that return props that will injected into your Component.

const mapSizesToProps = function(sizes) {
  const props = {
    backgroundColor: sizes.width < 700 ? 'red' : 'green',
  }

  return props
}

But you can simplify this to stay practical and elegant.

const mapSizesToProps = ({ width }) => ({
  backgroundColor: width < 700 ? 'red' : 'green',
})

Server Side Rendering

Since React Sizes rely on window to computate sizes, we can't computate the values in server enviroment. To try to get around this we can guess user viewport based on your user-agent, and pass values by a Context Provider.
But be careful, user-agent based detection is not a reliable solution. It's a workaround.

// Config can be created based on user-agent. See below
const config = { fallbackWidth: 360, fallbackHeight: 640 }

return (
  <SizesProvider config={config}>
    <App />
  </SizesProvider>
)

Example:

import MobileDetect from 'mobile-detect'
import Express from 'express'
import { SizesProvider } from 'react-sizes'
// All other imports

const getSizesFallback = userAgent => {
  const md = new MobileDetect(userAgent)

  if (!!md.mobile()) {
    return {
      fallbackWidth: 360,
      fallbackHeight: 640,
    }
  } else if (!!md.tablet()) {
    return {
      fallbackWidth: 768,
      fallbackHeight: 1024,
    }
  }

  return {
    fallbackWidth: 1280,
    fallbackHeight: 700,
  }
}

// Note: you don't need to use express, this is just an example
const app = new Express()
app.use((req, res) => {
  // ...
  const sizesConfig = getSizesFallback(req.headers['user-agent'])

  const App = (
    <AnotherProvider>
      <Router location={req.url}>
        <SizesProvider config={sizesConfig}>
          <Root />
        </SizesProvider>
      </Router>
    </AnotherProvider>
  )

  res.status(200)
  res.send(`<!doctype html>\n${ReactDOM.renderToString(<App />)}`)
  res.end()
})

app.listen(/* ... */)

Performance Notes

Shallow Compare

React Sizes do a shallow compare in props generated from mapSizesToProps (called propsToPass), so it will only rerender when they really change. If you create a deep data sctructure, this can generate false positives. In these cases, we recommend using immutable for a more reliable shallow compare result. Or just don't use deep data structures, if possible.

Contribute

You can help improving this project sending PRs and helping with issues.
Also you ping me at Twitter

More Repositories

1

react-powerplug

๐Ÿ”Œ [Unmaintained] Renderless Containers
JavaScript
2,686
star
2

github-blog

๐Ÿ™ Turn your github issues into a CMS for your blog.
TypeScript
390
star
3

bjson

ABANDONED! Bind Json: Reactive way to read/write json files.
JavaScript
72
star
4

janimate

jQuery Animate: jQuery animations with animate.css
JavaScript
69
star
5

react-bps

๐Ÿ”ฑ Create breakpoints to your component props
JavaScript
64
star
6

styn

๐Ÿ’Ž A small, zero-dependency, extensible, object to css generator
TypeScript
41
star
7

styleshape

๐Ÿ”ถ Because inline style can also be cool! [180 bytes only!]
JavaScript
41
star
8

lo-jsondb

Small database based on local .json files
JavaScript
40
star
9

next-jph

๐Ÿ“ JsonPlaceholder sample app made with Next.js
JavaScript
34
star
10

cartola-api

Implementaรงรฃo da API do CartolaFC em PHP
PHP
22
star
11

tibia-outfitter

New Tibia Outfitter.php
PHP
19
star
12

otinfo

Open Tibia Server Info Parser (otinfo). Catch information like players online, owner, motd, map weight, monsters, npcs, etc. passing IP and PORT.
PHP
18
star
13

otcts

Open Tibia Client in TS. Still WIP.
TypeScript
17
star
14

slaq

๐Ÿงฑ A lib to build Slack Apps, modular.
JavaScript
16
star
15

tibia-node-crawler

Tibia Crawler in nodejs
JavaScript
16
star
16

renatorib.github.io

My personal website
JavaScript
6
star
17

caixinha

Simple bundler for study
TypeScript
6
star
18

geo

TypeScript
6
star
19

covid19databr

For studying purposes.
JavaScript
4
star
20

slack-ui

Build slack Block Kit ui with JSX
3
star
21

curriculum-vitae

Renato Ribeiro, Frontend Engineer.
CSS
3
star
22

dot-notation

Node package to help you working with dot notation in objects
JavaScript
3
star
23

posts

rena.to posts source repo
2
star
24

caixa

TypeScript
2
star
25

cvb

Covid Vaccine Br
TypeScript
2
star
26

typed-ms

Typed MS
TypeScript
2
star
27

2048.js

fp 2048 lib
JavaScript
1
star
28

tibia-tasks

Build some automated tasks in tibia.com =)
HTML
1
star
29

2048-term

Play 2048 game in terminal
JavaScript
1
star
30

spinein

Spine like a shell spinner
JavaScript
1
star
31

renatorib

1
star
32

github-blog-tests

1
star
33

cra-material-ui

JavaScript
1
star
34

souls

Souls is a collection of CSS Animations that can also be handled by JavaScript.
1
star