1

I have been trying to implement react counterup along with react-visibility sensor. I wish to show the couterup only after that section is visible in the viewport. So, Using the visibility sensor to load it. But, it's not working and below is the error

"Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object."

Sample code is below

import React from 'react';
import CountUp, { startAnimation } from 'react-countup';

const CounterSection= (props) => {
    const VisibilitySensor = require('react-visibility-sensor');
    function onChange(isVisible) {
        console.log('Element is now %s', isVisible ? 'visible' : 'hidden');
    }
    return (
        <div>
            <VisibilitySensor onChange={onChange}>
                <div>...content goes here...</div>
                <CountUp start={0} end={9350} duration={5} />+
            </VisibilitySensor>
        </div>
    );
};

Assistance on this much appreciated. Thanks

SajZ
  • 262
  • 3
  • 16
  • Why do you have the require statement inside the component? – Brian Thompson Mar 10 '20 at 14:18
  • That's how it was mentioned in the read more document of visibility sensor plugin – SajZ Mar 11 '20 at 02:15
  • @BrianThompson ``` import React from 'react'; import CountUp, { startAnimation } from 'react-countup'; import VisibilitySensor from 'react-visibility-sensor'; const CounterSection= (props) => { function onChange(isVisible) { console.log('Element is now %s', isVisible ? 'visible' : 'hidden'); } return (
    +
    ); }; ```
    – SajZ Mar 11 '20 at 05:43
  • @BrianThompson The other way also didnt work – SajZ Mar 11 '20 at 05:44

4 Answers4

0

The error was that the contents inside any component should be within a single block. Also, visibility sensor should be imported and removed from required. I added the contents inside div and the error was off.

import CountUp, { startAnimation } from 'react-countup';
import VisibilitySensor from 'react-visibility-sensor';

const CounterSection= (props) => {

    function onChange(isVisible) {
        console.log('Element is now %s', isVisible ? 'visible' : 'hidden');
    }
    return (
        <div>
            <VisibilitySensor onChange={onChange}>
                <div>
                   <div>...content goes here...</div>
                   <CountUp start={0} end={9350} duration={5} />+
                </div>
            </VisibilitySensor>
        </div>
    );
};
SajZ
  • 262
  • 3
  • 16
0

As a previous poster pointed out, you're importing the library improperly, import it with an import statement at the top of the component. Using the ES5 require is correct for Node/Express but not for React.

You don't need to manually handle the onChange, that's apparently an older way of getting the two libraries to work with each other. Check out this answer pertaining to using VisibilitySensor and CountUp. I just tested it out and it works for me.

Nick Kinlen
  • 1,356
  • 4
  • 30
  • 58
0

VisibilitySensor does not support the feature to track the first time visibility out of the box. I will put here an example that I have been using.

AppearVisibility.js

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

/**
 * VisibilitySensor does not implement some kind of funcionality to track first time
 * visibility. This component extends VisibilitySensor compoment to provide this
 * feature. Just use `hasBeenVisible` render prop instead of `isVisible`.
 * 
 * https://github.com/joshwnj/react-visibility-sensor/issues/117#issuecomment-686365798
 */
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;

CounterSection.js

import React from 'react';
import CountUp from 'react-countup';

const CounterSection = (props) => {
  return (
    <div>
      <div>...content goes here...</div>
      <AppearSensor>
        {({ hasBeenVisible }) =>
          hasBeenVisible
            ? <CountUp
              start={0}
              end={9350}
              duration={5} />
            : <span>9350</span>
        }
      </AppearSensor>
    </div>
  );
};

export default CounterSection;
André Abreu
  • 737
  • 7
  • 13
0
import React, {Fragment,Component} from 'react';

import CountUp, { startAnimation } from 'react-countup';
import ReactVisibilitySensor from "react-visibility-sensor";

class Test extends Component {
    render() {
        return (
            <Fragment>
                <h1 className={'Countnumber'}>
                    <CountUp start={0} end={100} delay={0}>
                        {({ countUpRef,start }) => (
                            <ReactVisibilitySensor onChange={start} delayedCall={true}>
                                <span ref={countUpRef} />
                            </ReactVisibilitySensor>
                        )}
                    </CountUp>
                </h1>
            </Fragment>
        );
    }
}

export default Test;

This definitely works

David Buck
  • 3,752
  • 35
  • 31
  • 35