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

more convenient API #11

Closed
jedwards1211 opened this issue Apr 20, 2016 · 5 comments
Closed

more convenient API #11

jedwards1211 opened this issue Apr 20, 2016 · 5 comments

Comments

@jedwards1211
Copy link

jedwards1211 commented Apr 20, 2016

Inspired by the API of react-motion, I came up with this component today, before finding this repo. What do you think? It allows you to measure any DOM property or computedStyle attribute, and passes them to a child callback function that you use to render instead of having to setState. Obviously it doesn't use mutation observers but that could be integrated into this approach. What do you think? If you like it I could work on turning this into a PR for a new major version.

Using it looks like this:

function renderColumns(numColumns: number): React.Element {
  ...
}
const responsiveView = <Responsive domProps={['offsetWidth']}>
  {({offsetWidth}) => {
    let numColumns = offsetWidth ? Math.max(1, Math.floor(offsetWidth / 200));
    return offsetWidth ? renderColumns(numColumns) : null;
  }}
</Responsive>;

And here's the component:

/* @flow */

import React, {Component} from 'react';
import shallowEqual from 'fbjs/lib/shallowEqual';
import _ from 'lodash';

type Props = {
  domProps?: string[],
  computedStyleProps?: string[],
  children: (state: {computedStyle?: Object, [domProp: string]: any}) => ?React.Element,
  component: string
};

type DefaultProps = {
  component: string
};

type State = Object;

export default class Responsive extends Component<DefaultProps,Props,State> {
  static defaultProps = {
    component: 'div'
  };
  state: State = {
    remeasure: this.remeasure
  }; 
  mounted: boolean = false;
  root: ?Object;
  componentWillMount() {
    this.mounted = true;
  }
  componentDidMount() {
    this.remeasure();
    window.addEventListener('resize', this.remeasure);
  }
  componentWillReceiveProps(nextProps: Props) {
    if (!shallowEqual(this.props.domProps, nextProps.domProps) || 
        !shallowEqual(this.props.computedStyleProps, nextProps.computedStyleProps)) {
      this.remeasure();
    }
  }
  componentWillUnmount() {
    this.mounted = false;
    window.removeEventListener('resize', this.remeasure);
  }
  remeasure: Function = _.throttle(() => {
    const {root} = this;
    if (this.mounted && root) {
      let {domProps, computedStyleProps} = this.props;
      let nextState = {};
      if (domProps) {
        domProps.forEach(prop => nextState[prop] = root[prop]);
      }
      if (computedStyleProps) {
        nextState.computedStyle = {};
        let computedStyle = getComputedStyle(root);
        computedStyleProps.forEach(prop => nextState.computedStyle[prop] = computedStyle[prop]);
      }
      this.setState(nextState);
    } 
  }, 500);
  render(): ?React.Element {
    let {props: {children}, state} = this;
    let Comp: any = this.props.component;
    return <Comp ref={c => this.root= c} children={children(state)}/>;
  }
}
@souporserious
Copy link
Owner

I actually had this in the very first release https://github.com/souporserious/react-measure/tree/0.0.8 but I needed the ability to setState hence why it's that way now. I might be open to rework the component to accept a child function that passes in the dimensions if you need it for more simple cases. I've also been messing around with Higher Order Components and context.

@jedwards1211
Copy link
Author

jedwards1211 commented Apr 20, 2016

We could certainly support both, right? For instance if this.props.children is a function, call it with the state, and otherwise keep the current approach (of course onMeasure could be supported in either case).

@jedwards1211
Copy link
Author

jedwards1211 commented Apr 20, 2016

Plus I think the ability to specify any random DOM property or computedStyle attribute one wants to read is nice and would fit into with the premise of this library well

@souporserious
Copy link
Owner

souporserious commented Jun 27, 2016

Sorry for the long wait. It's finally implemented in 0.4.0 🎉

See usage here

@jedwards1211
Copy link
Author

Oh, cool! Thanks!

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

No branches or pull requests

2 participants