joshwnj / react-visibility-sensor

Sensor component for React that notifies you when it goes in or out of the window viewport.
MIT License
2.33k stars 195 forks source link

`Once` prop #117

Open GeeWizWow opened 6 years ago

GeeWizWow commented 6 years ago

Any chance of getting a once prop, that would only trigger the event once ?

nirpeled commented 6 years ago

+1

fiso commented 6 years ago

For the record, you can very easily emulate this functionality by using the active prop, assuming you have your visibility-state stored.

  onChangeVisibility (isVisible) {
    this.setState({visible: isVisible});
  }

  render () {
      <VisibilitySensor onChange={this.onChangeVisibility} active={!this.state.visible} />
  }
MonliH commented 4 years ago

I know this suggestion is quite old, but are there any plans to implement this? The Once prop would be one of those features that make this library better than others.

omarryhan commented 4 years ago

Someone made a PR for this: https://github.com/joshwnj/react-visibility-sensor/pull/143

Hassene66 commented 4 years ago

For those who uses functional components


[State ,setState] = useState({visible: false });

const onChangeVisibility = isActive => {
    setState({ ...State, visible: isActive });
}
 <VisibilitySensor  onChange={e => onChangeVisibility(e)} active={!State.visible} />
robbertvancaem commented 4 years ago

Until #143 is merged, today I came up with this simple solution.

// components/sensor.js
import React, { useState } from "react";
import VisibilitySensor from "react-visibility-sensor";
import PropTypes from "prop-types";

const Sensor = ({ children, once }) => {
  const [visible, setVisible] = useState(false);

  return (
    <VisibilitySensor
      active={once ? !visible : true}
      onChange={(isVisible) => {
        if (visible && once) {
          return;
        }

        setVisible(isVisible);
      }}
    >
      {children({ isVisible: visible })}
    </VisibilitySensor>
  );
};

Sensor.propTypes = {
  children: PropTypes.func.isRequired,
  once: PropTypes.bool,
};

Sensor.defaultProps = {
  once: false,
};

export default Sensor;

You can then use it like so:

// components/something.js
import Sensor from './sensor';

<Sensor key={title} once>
    {({ isVisible }) => (<div className={`hello ${isVisible && "is-visible"}`}>Something</div>)}
</Sensor>
MonliH commented 4 years ago

If you really need this functionality and don't want to write some extra code yourself, you could also try react-on-screen, which seems to support the feature.

abreu-dev commented 4 years ago

I just want to share my solution. It would be great if this library has the hasBeenVisible render prop out of the box.

import React, { useState } from "react";
import VisibilitySensor from "react-visibility-sensor";

const AppearSensor = ({
  onChange,
  children,
  ...rest
}) => {
  const [hasBeenVisible, setHasBeenVisible] = useState(false);

  return (
    <VisibilitySensor {...rest} onChange={(isVisible) => {
      if (isVisible) setHasBeenVisible(true)
      if (onChange) onChange(isVisible)
    }}>
      {
        ({
          isVisible,
          ...restRenderProps
        }) => {
          return children({ isVisible, ...restRenderProps, hasBeenVisible })
        }
      }
    </VisibilitySensor>
  );
};

AppearSensor.propTypes = VisibilitySensor.propTypes
AppearSensor.defaultProps = VisibilitySensor.defaultProps

export default AppearSensor;
katsos commented 3 years ago

This missing feature is the only one made me go with react-on-screen. If you need a contribution feel free to reach me.