最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React: UI Flickering When State Updated - Stack Overflow

programmeradmin1浏览0评论

I have a component that displays search data returned from the Spotify API. However, every time I update the state the UI flickers:

Input:

            <DebounceInput
                debounceTimeout={300}
                onChange={handleChange}
            />

Hook:

const [searchResults, setSearchResults] = useState(null)

API call w/ Apollo:

 const searchSpotify = async (query) => {
    const result = await props.client.query({
        query: SearchTracks,
        variables: {
            query
        }
    })
    const tracks = result.data.searchedTracks
    setSearchResults(tracks)
}

Render:

        {searchResults &&
            <div className="search-results">
                    {searchResults.map((song) => (
                            <SongInfo key={song.id} {...song} />
                    ))}
            </div>
        }

I noticed it only happens on the first load. For example, if I were to type the query again it shows without flickering. Is there a better way to implement this so the UI doesn't flicker?

I have a component that displays search data returned from the Spotify API. However, every time I update the state the UI flickers:

Input:

            <DebounceInput
                debounceTimeout={300}
                onChange={handleChange}
            />

Hook:

const [searchResults, setSearchResults] = useState(null)

API call w/ Apollo:

 const searchSpotify = async (query) => {
    const result = await props.client.query({
        query: SearchTracks,
        variables: {
            query
        }
    })
    const tracks = result.data.searchedTracks
    setSearchResults(tracks)
}

Render:

        {searchResults &&
            <div className="search-results">
                    {searchResults.map((song) => (
                            <SongInfo key={song.id} {...song} />
                    ))}
            </div>
        }

I noticed it only happens on the first load. For example, if I were to type the query again it shows without flickering. Is there a better way to implement this so the UI doesn't flicker?

Share Improve this question edited Mar 6, 2019 at 21:42 Travis S. asked Mar 6, 2019 at 21:06 Travis S.Travis S. 3431 gold badge4 silver badges14 bronze badges 8
  • You could add a loading state where when you make the api call to fetch you toggle a loading flag/state. – varoons Commented Mar 6, 2019 at 21:33
  • Have you tried adding key prop to your SongInfo element? Something like, <SongInfo key={song.id} {...song} /> (change id to whatever property uniquely identifies your song). Adding key prop to list items improves React performance. – abadalyan Commented Mar 6, 2019 at 21:37
  • @varoons The loading state happens so quickly that it actually makes the UI worse – Travis S. Commented Mar 6, 2019 at 21:43
  • @abadalyan I have a key in my actual code, I tried simplifying it for this question. I edited the <SongInfo> component to clarify – Travis S. Commented Mar 6, 2019 at 21:44
  • If you replace SongInfo with simple <div>{song.name}</div> does it flicker? – abadalyan Commented Mar 6, 2019 at 21:50
 |  Show 3 more comments

2 Answers 2

Reset to default 7

Below are the frames that cause the flicker. What I think is happening is it takes some time for the images to load. While they are loading the items have reduced height. You should make sure SongInfo layout does not depend on whether the image has been loaded or not.

Images not loaded - items are collapsed:

Images were loaded:

I think whats happening is that you are executing a search query on every key stroke which is causing the weird behavior.

Use lodash debounce to avoid doing a search on every key stroke. That should address the flickering. (Also, adding a loading state will help)

Sample debounce component

import React, {Component} from 'react'
import { debounce } from 'lodash'

class TableSearch extends Component {

  //********************************************/

  constructor(props){
    super(props)

    this.state = {
        value: props.value
    }

    this.changeSearch = debounce(this.props.changeSearch, 250)
  }

  //********************************************/

  handleChange = (e) => {
    const val = e.target.value

    this.setState({ value: val }, () => {
      this.changeSearch(val)
    })
  }

  //********************************************/

  render() {

    return (
        <input
            onChange = {this.handleChange}
            value = {this.props.value}
        />
    )
  }

  //********************************************/

}
发布评论

评论列表(0)

  1. 暂无评论