ztorstri
ztorstri

Reputation: 389

How can I reuse component logic

I am implementing a custom table that will have pagination, filtering, sorting, and other common features. I do not want to use an existing solution, both because this is a good exercise to get familiar with React and because I want the table tailored to my needs.

The issue I'm running into is with the filtering. What I want is to put the "does object pass filter" logic in the Filter; I've used this pattern successfully in other languages and it's very clean.

However, with React all of the logic has to go in the parent because the parent can't call methods on the child. So I'm stuck.

Here's what I want to do, roughly.

class FilterContainer extends Component {
  constructor(props) {
    super(props);

    this.toggle = this.toggle.bind(this);

    this.state = { isOpen: false };
  }

  toggle() {
    this.setState({ isOpen: !this.state.isOpen });
  }

  render() {
    return (
      <Fragment>
        <FaFilter id="filter-icon" />
        <Popover placement="right" isOpen={this.state.isOpen} target="filter-icon" toggle={this.toggle}>
          <PopoverHeader>Filter table</PopoverHeader>
          <PopoverBody>
            {this.props.children}
          </PopoverBody>
        </Popover>
      </Fragment>
    );
  }
};

class Filter extends Component {
  constructor(props) {
    super(props);

    this.setValue = this.setValue.bind(this);
  }

  setValue(event) {
    this.props.setValue(this.props.name, event.target.value);
  }

  // I want this as a method on the filter because I will have different types of
  // filters, and I don't want to duplicate this everywhere I use a filter
  passesFilter(obj){
    if (obj.hasownproperty(this.props.name)){
      if (obj[this.props.name].contains(this.props.value)){
        return true;
      }
    }
  }

  render() {
    return (
      <Fragment>
        <Label>
          {this.props.name}

          <Input
            id={this.props.name + "-value"}
            type="text"
            value={this.props.value}
            onChange={this.setValue} />
        </Label>
      </Fragment>
    );
  }
};

But now imagine instead of Filter, I had a StringFilter which could handle case sensitivity and regex, a BoolFilter which is just true/false, maybe a DateFilter, etc. Each one of those has the concept of "passes filter", and duplicating them in the DataTable as well as anywhere else I want to use them sucks.

Hopefully this makes sense, if not I can provide more detail.

Upvotes: 3

Views: 80

Answers (1)

antho39
antho39

Reputation: 78

You can create a filter library function and import some and stack the filter result For example

Filter/Date
myFilterDateBetween(DateA, DateB, DateC){ 
  //true false
}
myFilterDateBefore(DateA, DateB){ 
  //true false
}

// other DateFilter

Filter/Boolean
filterIsTrue(Bool){ 
  //true false
}

// other BooleanFilter

Filter/...type
//other filter base on type:

And after import filter where you need it and call them

import myFilterDateBetween from 'Filter/Date'
import MyOtherFilterBoolean from 'Filter/Boolean'

data.filter( 
   (item)=>myFilterDateBetween(item.date,dateA, dateB)
).filter(
    (item)=>MyOtherFilterBoolaen(item.Boolean, true)
)

I hope this can help you

Upvotes: 1

Related Questions