2

I created a custom text pagination component(displaying the current pagination information. For example 1-N of total), and I found myself adding repeating code to the parent components(ComponentA and ComponentB). Every time I need to add the TextPagination component to the parent components, I need to add the same state and callback methods. If you look at ComponentA and ComponentB, they both have this.state = { itemCount: 0 } and the onDisplayLessData and onDisplayMoreData callback methods. This is something that I want to avoid, and especially, when other developers need to use the TextPagination component, they need to remember to add all of this...not so great in my opinion.

Component A

class ComponentA extends React.Component {
  constuctor() {
    super();
    this.state = { itemCount: 0 }
  } 
  render(){
    // re-render data
    <TextPagination .../>
 }

  onDisplayMoreData(){}
  onDisplayLessData(){}
}

Component B

class ComponentB extends React.Component {
  constuctor() {
    super();
    this.state = { itemCount: 0 }
  } 
  render(){
    // re-render data
    <TextPagination .../>
  }

  onDisplayMoreData(){ //when child updates, this gets called }
  onDisplayLessData(){ //when child updates, this gets called }
}

TextComponent

class TextPagination extends React.Component {

    constructor() {
        super();
        this.state = { itemCount: 0, showLess: false };
        this.displayMoreData = this.displayMoreData.bind(this);
        this.displayLessData = this.displayLessData.bind(this);
    }

    render() {}

   displayMoreData(value) {
     // more code
     // callback to notify the parent component
     this.props.onDisplayMoreData(value);
   }

   displayLessData(value) {
     // more code
     // callback to notify the parent component
     this.props.onDisplayLessData(value);
   }
}

So, I figure to create another class called Pagination with this.state = { itemCount: 0 } and the callback methods, and have it extends to React.Component. Then ComponentA and ComponentB can extend from Pagination class.

Example:

class Pagination extends React.Component {

    constructor() {
        super();
        this.state = {
            itemCount: 0            
        };

        this.onDisplayMoreData = this.onDisplayMoreData.bind(this);
        this.onDisplayLessData = this.onDisplayLessData.bind(this);
    }

    onDisplayMoreData(itemCount) {
        this.setState({
            itemCount: itemCount
        });
    }

    onDisplayLessData(itemCount) {
        this.setState({
            itemCount: itemCount
        });
    }

} 

ComponentA extends Pagination {
  constructor() { super(); }
  render() {
    // re-render data
    <TextPagination .../>
  }
}

ComponentB extends Pagination {
  constructor() { super(); }
  render() {
    // re-render data
    <TextPagination .../>
  }
}

This approach seems to work without any problems. ComponentA and ComponentB no longer have to have the state and callback methods.Other developers do not need to remember to add the state and callback methods when using TextPagination.

Is this the right solution? If not, please give me some advice.

Darn it, it just occurred to me if ComponentA or ComponentB needs to add additional state, then it will overwrite the original parent's state...is that correct?

Thanks for your help!

2
  • 1
    Two choices I would think about: 1) keep it pure, props are passed in and through (no state), if you need the props to change you fire a callback and expect the implementor to modify state. 2) use state but keep it at your top level and pass it down as props, if the children need to e.g. increment the page index, they should through a callback to the parent Commented Dec 22, 2016 at 14:54
  • Thank you, this may me realized that I had state in both parent and child components. I need to do a little bit of refactoring. Commented Dec 22, 2016 at 15:27

1 Answer 1

5

Sounds like you want is a Higher Order Component. HOCs are really just functions that take a react component and return a new react component that has some form of extended functionality. In this case, the pagination functionality. It would look something like this:

const Pagination = (WrappedComponent) => {
  return class Pg extends React.Component {

    constructor(props) {
        // don't forget to call super with props!
        super(props);
        this.state = {
            itemCount: 0            
        };

        this.onDisplayMoreData = this.onDisplayMoreData.bind(this);
        this.onDisplayLessData = this.onDisplayLessData.bind(this);
    }

    onDisplayMoreData(itemCount) {
        this.setState({
            itemCount: itemCount
        });
    }

    onDisplayLessData(itemCount) {
        this.setState({
            itemCount: itemCount
        });
    }

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

Then, when you want to create a component with pagination (eg. ComponentA), you'd export it like so:

export default Pagination(ComponentA)

Some extra reading for you about HOCs: https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775 https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e#.5riykqsso

Hope this helps!

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, I will give this a try. I'm not understanding the export part, but it looks like this is what I'm after. I will let you know if it works. Thanks!
I'm sorry, I meant that I don't understand how it works. I know what export default means, but I do not understand how to use export default Pagination(ComponentA). This will be inside the pagination file, and when I use it, I would do import Pagination from 'pagination', then const p = Pagination(ComponentA)??? That doesn't make sense.
No, you would put that in the ComponentA file. Instead of doing export default ComponentA, you would do export default Pagination(ComponentA). This way, you are exporting the wrapped component
Ok...got you. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.