12Noone
12Noone

Reputation: 83

React Component Flickers on Rerender

I'm pretty new to react and have been working on this new page for work. Basically, there's a panel with filter options which lets you filter objects by color. Everything works but I'm noticing the entire filter panel flickers when you select a filter.

Here are the areas functions in the filter component I think bear directly on the filter and then the parent component they're inserted into. When I had originally written this, the filter component was also calling re render but I've since refactored so that the parent handles all of that - it was causing other problems with the page's pagination functionality. naturally. and I think that's kind of my problem. the whole thing is getting passed in then rerendered. but I have no idea how to fix it. or what's best.

checks whether previous props are different from props coming in from parent and if so, creates copy of new state, calls a render method with those options. at this point, still in child component.

componentDidUpdate(prevProps, prevState) {
if (prevState.selectedColorKeys.length !== this.state.selectedColorKeys.length ||
    prevState.hasMatchingInvitation !== this.state.hasMatchingInvitation) {
  const options = Object.assign({}, {
    hasMatchingInvitation: this.state.hasMatchingInvitation,
    selectedColorKeys: this.state.selectedColorKeys
  });
  this.props.onFilterChange(options);
  }
}

handles active classes and blocks user from selecting same filter twice

isColorSelected(color) {
  return this.state.selectedColorKeys.indexOf(color) > -1;
}

calls to remove filter with color name so users can deselect with same filter button or if its a new filter, sets state by adding the color to the array of selected color keys

filterByColor(color) {
  if (this.isColorSelected(color.color_name)) {
    this.removeFilter(color.color_name);
    return;
} 
this.setState({
  selectedColorKeys: 
  this.state.selectedColorKeys.concat([color.color_name])
  });
}

creating the color panel itself

// color panel
colorOptions.map(color => (
    colorPicker.push(
      (<li className={['color-filter', this.isColorSelected(color.color_name) ? 'active' : null].join(' ')} key={color.key} ><span className={color.key} onClick={() => { this.filterByColor(color); }} /></li>)
    )
));

parent component

callback referencing the filter child with the onFilterChange function

<ThemesFilter onFilterChange={this.onFilterChange} />



onFilterChange(filters) {
const { filterThemes, loadThemes, unloadThemes } = this.props;
unloadThemes();
this.setState({
  filterOptions: filters,
  offset: 0
}, () => {
  filterThemes(this.state.filterOptions.selectedColorKeys, this.state.filterOptions.hasMatchingInvitation);
  loadThemes(this.state.offset);
  });
}

when I place break points, the general flow seems to be :

  1. filterByColor is triggered in event handler passing in that color
  2. active classes are added to the color, a filter tag for that color is generated and appended
  3. componentDidMount takes in the previous props/state and compares it to the new props/state. if they don't match, i.e state has changed, it creates a copy of that object, assigning the new states of what's changed. passes that as props to onFilterChange, a function in the parent, with those options.
  4. onFilterChange takes those options, calls the action method for getting new themes (the filtering actually happens in the backend, all I really ever need to do is update the page) and passes those forward. its also setting offset to 0, that's for the page's pagination functionality.

It looks like the problem might be around the componentDidUpdate function which, after setting breakpoints and watching it go through the steps from filterByColor to componentDidMount, that componentDidMount loops through twice, checking again if the colorIsSelected, and throughout all that the color panel pauses to re-render and you get a flicker.

Is it possible creating the copy is causing it? since it's being treated, essentially, as a new object that isColorSelected feels necessary to double check? any help you guys have would be much appreciated, this shit is so far over my head I can't see the sun.

Upvotes: 1

Views: 4304

Answers (1)

bennygenel
bennygenel

Reputation: 24660

Can you change

componentDidUpdate(prevProps, prevState)

with

componentWillUpdate(nextProps, nextState)

Upvotes: 1

Related Questions