簡體   English   中英

組件僅在單擊兩次后更新

[英]Component only updates after two clicks React

我正在構建一個React應用程序,除其他功能外,該應用程序會在單擊按鈕時生成一個隨機數,然后將JSON對象數組過濾為該隨機數索引處的一個(即JSON [random])。 通常,應該在過濾了JSON對象數組之后重新渲染該應用程序,但是由於某些原因,第一次單擊該按鈕並選擇一個隨機變量時,需要兩次單擊才能更新。 從那時起,它會按預期進行更新,每次單擊按鈕時都會使用新的隨機渲染。

我不確定問題是來自App.js還是更低的地方。 第一次單擊時,它會生成一個新的隨機數,並且可以將其保存為狀態,但無法立即重新渲染。 在隨后的點擊中,事情似乎是根據先前生成的隨機數進行更新的,而新的隨機數則被放入隊列中。 我希望所有這些都可以一次性完成:單擊,生成隨機,保存到狀態,更新以反映新的隨機JSON [random]。

這可能與我實現生命周期方法的方式有關,因為我承認我不確定每種方法的所有細微差別,並且只是嘗試使用任何一種似乎可以滿足我要求的方法。 如果您有任何建議,請告訴我...

謝謝!

以下是相關文件:

App.js-在Header.state.randomClicks中注冊新點擊時生成並存儲隨機數的地方

class App extends Component {
  constructor(props){
    super(props)
    this.state = {headerLink: "", searchValue: "", random: 0, randomClicks: 0}

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

  getLinkFromHeader = (link) => {
    if (this.state.headerLink !== link) {
      this.setState({
        headerLink: link,
      })
    }
  }

  getSearchValueFromHeader = (string) => {
    this.setState({
      searchValue: string,
    });
  }

  getRandomMax = (max) => {
    this.setState({
      randomMax: max,
    })
  }

  getRandomClicks = (value) => {
    this.setState({
      randomClicks: value,
    })
  }

  generateRandom(number) {
    let random = Math.floor(Math.random() * number) + 1;
    console.log("generateRandom = ", random)
    return random
  }

  shouldComponentUpdate(nextProps, nextState) {
    return this.state.randomClicks !== nextState.randomClicks;
  }

  componentWillUpdate() {}

  componentDidUpdate(prevState) {
    let randomClicks = this.state.randomClicks;
    console.log("this.state.randomClicks: ", this.state.randomClicks)
    // console.log("prevState: ", prevState)
    // console.log("prevState.randomClicks = ", prevState.randomClicks)
    // ^^ is this a bug ? ^^
    let random = this.generateRandom(this.state.randomMax);
    if (this.state.random !== random) {
      this.setState({random: random})
    }
  }

  render() {
    return (
      <div className="App background">
        <div className="content">
          <Header getLinkFromHeader={this.getLinkFromHeader} getSearchValueFromHeader={this.getSearchValueFromHeader} randomClick={this.randomClick} getRandomClicks={this.getRandomClicks}/>
          <TilesContainer link={this.state.headerLink} searchValue={this.state.searchValue} getRandomMax={this.getRandomMax} random={this.state.random} randomClicks={this.state.randomClicks}/>
        </div>
      </div>
    );
  }
}

export default App

Header.js * -每次單擊RandomButton時都會增加randomClick計數

class Header extends Component {
  constructor(props){
    super(props);
    this.state = { selectorLink: "", searchValue: "", randomClicks: 0 }

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


  getLinkFromSelector = (link) => {
    this.setState({
      selectorLink: link,
    })
  }

  getSearchValue = (string) => {
    this.setState({
      searchValue: string,
    })
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("this.state !== nextState: ", this.state !== nextState)
    return this.state !== nextState;
  }

  componentDidUpdate(previousState){
    if(this.state.selectorLink !== previousState.selectorLink) {
      this.props.getLinkFromHeader(this.state.selectorLink);
    }
    this.props.getSearchValueFromHeader(this.state.searchValue);
    this.props.getRandomClicks(this.state.randomClicks);
    console.log("Header Did Update")
  }

  randomClick(){
    this.props.randomClick;
    this.setState({
      randomClicks: this.state.randomClicks += 1,
    });
  }

  render(){
    return(
      <div id="header" className="header">

        <div className="title-div">
          <div className="h1-wrapper title-wrapper">
            <h1>Pokédex Viewer App</h1>
          </div>
        </div>

        <PokedexSelector  getLinkFromSelector={this.getLinkFromSelector}/>

        <SearchBar getSearchValue={this.getSearchValue}/>

        <button type="button" id="random-button" onClick={this.randomClick}>Random Pokémon</button>
        <button type="button" id="show-all-button" onClick={this.showAllClick}>Show All</button>

      </div>
    )
  }
}

export default Header

TilesContainer.js-發送來自App的隨機數,並過濾/重新渲染圖塊列表

class TilesContainer extends Component {

  constructor(props){
    super(props);
    this.state = {
        pokemon: [],
        filteredPokemon: [],
        randomMax: 0,
        showDetails: false,
      };
    this.getPokemon = this.getPokemon.bind(this);
    this.tiles = this.tiles.bind(this);
    this.getPokemon(this.props.link);
  }

  getPokemon(pokedexLink) {
    let link = "";
    (pokedexLink === "")
      ? link = "https://pokeapi.co/api/v2/pokedex/national/"
      : link = this.props.link;
      fetch(link)
      .then(response => response.json())
      .then(myJson => {
        let list = myJson['pokemon_entries'];
        this.setState({
          pokemon: list,
          randomMax: list.length,
        })
        this.props.getRandomMax; // send randomMax to App
      })
  }

  filterPokemon(string) {
    if (string !== "") {
        console.log("string: ", string)
        string = string.toString().toLowerCase()
        let filteredPokemon =  this.state.pokemon.filter(pokemon => {
        const name = pokemon.pokemon_species.name;
        const nameStr = name.slice(0,string.length);
        const number = pokemon.entry_number;
        const numberStr = number.toString().slice(0, string.length);
        return (this.state.random !== 0) ? number.toString() === string : nameStr === string || numberStr === string;
      })
      if (this.props.randomClicks !== 0) { // i.e. using a random
        this.setState({
          filteredPokemon: filteredPokemon,
        })
      } else {
        this.setState({
          filteredPokemon: filteredPokemon,
          randomMax: filteredPokemon.length,
        })
      }
    } else {
      this.setState({
        filteredPokemon: [],
        randomMax: this.state.pokemon.length,
      })
    }
  }


  componentDidUpdate(prevProps, prevState) {
    if (this.props.link !== prevProps.link) {
      this.getPokemon(this.props.link)
    }
    if (this.props.searchValue !== prevProps.searchValue) {
      this.filterPokemon(this.props.searchValue)
    }
    if (this.state.randomMax !== prevState.randomMax){
      this.props.getRandomMax(this.state.randomMax);
    }
    if (this.props.random !== prevProps.random) {
      console.log("TilesContainer random: ", this.props.random)
      this.filterPokemon(this.props.random)
    }
  }

  tiles() {
    console.log("tiles() filteredPokemon: ", this.state.filteredPokemon)
    console.log("tiles() searchValue: ", this.props.searchValue)
    console.log("tiles() random: ", this.props.random)
    if (this.state.pokemon.length > 0) {
      if (this.state.filteredPokemon.length == 0 && this.props.searchValue === ""){
        return (
            this.state.pokemon.map(pokemon => (
            <Tile key={pokemon.entry_number} number={pokemon.entry_number} name={pokemon.pokemon_species.name} url={pokemon.pokemon_species.url}/>
          ))
        )
      } else if (this.state.filteredPokemon.length > 0){
        return (
            this.state.filteredPokemon.map(pokemon => (
            <Tile key={pokemon.entry_number} number={pokemon.entry_number} name={pokemon.pokemon_species.name} url={pokemon.pokemon_species.url}/>
          ))
        )
      }

    }
  }

  render(){
    return (
      <div id="tiles-container"
           className="tiles-container">
             {this.tiles()}
      </div>
    )
  }
}

export default TilesContainer

您不應在setState使用當前狀態,也不應直接修改狀態。 而且您實際上並沒有調用this.props.randomClick ,它是未定義的。 更改

randomClick(){
    this.props.randomClick;
    this.setState({
        randomClicks: this.state.randomClicks += 1,
    });
}

randomClick(){
    if (typeof(this.props.randomClick) === 'function') this.props.randomClick();
    this.setState(olState => ({
        randomClicks: olState.randomClicks + 1,
    }));
}

還要檢查您的shouldComponentUpdate方法。 他們可能是越野車或多余的。 看起來您在state.random更改時阻止更新App 因此,每次單擊按鈕時,您都會存儲新的隨機值,但會使用前一個隨機值。 因此,對於初始渲染和首次單擊,請使用random: 0

而且我猜getRandomClicks應該是setRandomClicks

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM