0

I found this code online and because I'm new to React wanted to know how to use it without getting this error.

this.props.children is not a function

From what I gather its listing to the body scroll position and trying to pass it as props to any React children its wrapped around. Am I correct ?

If so why the above error when I use it like below.

import React, {Component} from 'react';
import Nav from './nav';
import styles from '../../styles/header.scss';
import bgCover from '../../images/homeslider.jpg';
import Scroll from '../utils/scroll';

export default class Header extends Component{

    render(){
        return(
            <Scroll>
                <div id='header'>
                    <div className="container">
                        <img src={bgCover} id='bg-cover' alt="background-image" />
                        <div id="temp-text">HEADER</div>
                        <Nav />
                    </div>
                </div>
            </Scroll>
        )
    }

}

This is the scroll.js file

import React, {Component} from 'react';

export default class Scroll extends Component {
  constructor(props) {
    super(props);

    this.state = { scrollTop: 0,
                   scrollLeft: 0 };

    window.addEventListener('scroll', event => {
      this.setState({ scrollTop: document.body.scrollTop,
                      scrollLeft: document.body.scrollLeft});
    });
  }

  render() {
    return this.props.children(this.state.scrollTop, this.state.scrollLeft)
  }
}
me-me
  • 5,139
  • 13
  • 50
  • 91

1 Answers1

1

As Andrew mentions, this.props.children is not a function. In your render function, if you wanted to render the children components, then your render would be written something like this.

 render() {
    return (
      <div>
        {this.props.children}
      </div>
    )
  }

In your example, the code above would place this JSX block

       <div id='header'>
            <div className="container">
                <img src={bgCover} id='bg-cover' alt="background-image" />
                <div id="temp-text">HEADER</div>
                <Nav />
            </div>
        </div>

into your Scroll component, because they are the children (nested) components.

Now, it looks like you want to pass props to your children components. You can do this by adding accessing React.Children.

An nice example of passing a function as a prop to all children components can be found here :

doSomething: function(value) {
  console.log('doSomething called by child with value:', value);
}
const childrenWithProps = React.Children.map(this.props.children,
 (child) => React.cloneElement(child, {
   doSomething: this.doSomething
 })
);

return <div>{childrenWithProps}</div>
Community
  • 1
  • 1
Yo Wakita
  • 5,322
  • 3
  • 24
  • 36
  • Ah thanks this makes a little more sense. Its the second part i'm after the passing a function as a prop to all children components. Does the clone add any overhead or is it just cloning a virtual element. – me-me Feb 14 '17 at 22:14
  • Realistically, theres basically no extra overhead if any at all. You can see in this test that compares cloneElement vs createElement here: https://jsperf.com/react-createelement-vs-react-cloneelement – Yo Wakita Feb 14 '17 at 22:23
  • I also just figured out in my example you can also do this. { scrollTop =>
    {scrollTop}
    }
    – me-me Feb 14 '17 at 22:31
  • I didn't know you could just warp it all in curly braces and pass a fucntion directly in which is what the scroll.js demands. I guess that was my question. But you have explained a cleaner way. Thank you. – me-me Feb 14 '17 at 22:31