【问题标题】:Calling a function each time a component is rendered, since componentDidMount() only triggers once每次渲染组件时调用一个函数,因为 componentDidMount() 只触发一次
【发布时间】:2018-09-26 23:52:36
【问题描述】:

编辑:经过进一步测试,我意识到 componentDidMount 的行为符合我的预期,但这似乎是我的随机函数的问题,如果它再次运行,则由于某种原因返回未定义,所以在初始安装它会给我结果,当我再次安装它时它返回未定义,因此没有任何渲染......

我已进行研究以了解我遇到此问题的原因。我有一个 webapp 的组件,它只是一个将呈现赞助商名称的横幅。每次渲染此横幅时,我都想随机化赞助商出现的顺序。我可以让它工作,但它只在第一次渲染时发生(在 componentDidMount() 上),然后每次我访问该组件被渲染的任何部分时,它不再调用 componentDidMount() 所以它不渲染任何内容。

起初我认为每次进入调用该组件的部分时都应该调用 componentDidMount()。阅读后,到处都说组件被安装一次,这就是为什么它只调用一次函数。我怎样才能让它在我每次渲染组件时随机化?

这是我正在编写的代码示例。

class SponsorBanner extends React.Component {
    constructor(props){
        super(props)
        this.state = {
            randomized: []
        }

        this.randomizeSponsors = this.randomizeSponsors.bind(this)
    }

    randomizeSponsors(){
        let copy = []
        const array = ['a','b','c','d']
        let n = array.length
        let i;

        while(n){
            i = Math.floor(Math.random() * n--)
            copy.push(array.splice(i,1)[0])
        }

        let randomizedArray = copy.map((sponsor,i) => <div key={i}>{sponsor}</div>)

        this.setState({randomized:randomizedArray})

    }
    componentDidMount(){
        this.randomizeSponsors()
    }


    render(){

        return (
            <div>
                {this.state.randomized}
            </div>
        )
    }
}

此组件在应用程序的 2 个不同部分中呈现。这是一个非常简单的应用程序,我什至没有向它添加路由。它只是完全作为一个 SPA 工作。当用户单击一个部分时,它会呈现该组件。在第一次加载时,如果我访问呈现此组件的部分,它会显示一个随机数组。如果我导航到另一个部分并返回,它会呈现一个空横幅。

为什么会发生这种情况,我该如何解决?

【问题讨论】:

  • 你为什么首先将随机值存储在状态中?有没有不想改变的情况?
  • 嗯,我不习惯,在其他情况下,将它保存在我的函数中的状态中,这样我就可以渲染状态,这样当它发生变化时,它就会呈现变化。不过,这通常用于 fetch 调用,因此在这种情况下可能没有必要。
  • 你在使用 react-router 吗?也许你可以看看withRoutercomponentDidUpdate
  • 嘿 @bozdoz 不,我没有在这个特定的应用程序中使用 react-router 或任何路由,因为它非常简单,并且只有 3 个部分基本上像标签一样工作
  • @xunux 只是说:组件需要知道您何时想要更改某些内容。也许看看反应上下文api?我认为您不应该使用redux。如果该组件是选项卡的子组件,您可以传递一个独特的道具来改变它……只是想帮助您想出一种方法来实现这一点。祝你好运。

标签: javascript reactjs react-lifecycle


【解决方案1】:

如果您希望每 x 个 milliseconds 更改一次,则另一种方法是使用 asetIterval

工作示例:https://codesandbox.io/s/k9zz9wq9lo

import random from "lodash/random";
import React, { Component } from "react";

export default class Banner extends Component {
  state = {
    randomIndex: 0
  };

  componentDidMount = () => this.setTimer();

  componentWillUnmount = () => this.clearTimer();

  clearTimer = () => clearInterval(this.timeout);

  timer = () => this.setState({ randomIndex: random(0, 999) });

  setTimer = () => (this.timeout = setInterval(this.timer, 3000));

  render = () => (
    <img
      src={`https://loremflickr.com/600/100?lock=${this.state.randomIndex}`}
    />
  );
}

或者,如果您不想使用setIterval 并且该组件始终处于挂载状态...并且您只希望它在状态更改时更改...然后使用HOC 组件管理状态。然后,您可以利用HOCrender 方法更新变量。

工作示例:https://codesandbox.io/s/6qvl49vqw

import random from "lodash/random";
import React, { Component } from "react";
import Sample from "./Sample";

export default class Parent extends Component {
  state = {
    loadC1: false
  };

  shouldComponentUpdate = (nextProps, nextState) =>
    this.state.loadC1 !== nextState.loadC1;

  handleClick = () =>
    this.setState(prevState => ({ loadC1: !this.state.loadC1 }));

  render = () => {
    const randomIndex = random(0, 999);
    const { loadC1 } = this.state;

    return (
      <div style={{ textAlign: "center" }}>
        <button
          className="uk-button uk-button-primary"
          onClick={this.handleClick}
        >
          {!loadC1 ? "Show" : "Hide"} Component
        </button>
        <div style={{ marginBottom: 40 }}>
          {loadC1 && <Sample />}
        </div>
        <img src={`https://loremflickr.com/600/100?lock=${randomIndex}`} />
      </div>
    );
  };
}

【讨论】:

    【解决方案2】:

    如果您希望在每个 render 调用中随机分配数字,请将该逻辑添加到您的 render 函数中:

    render() {
      const randomized = this.randomizeSponsors(); // IMPORTANT: CHANGE THIS TO MAKE IT RETURN ARRAY INSTEAD OF SETSTATE
      return (
        <div>
          {randomized}
        </div>
      );
    }
    

    【讨论】:

    • 这是有道理的,我试过了,但由于某种原因它不起作用。如果我在返回结果之前将函数 randomizeSponsors() console.log 设为结果,控制台会在控制台中显示随机数组,然后重新打印一个空数组。这意味着该函数被调用了两次,并且由于某种原因第二次围绕数组返回空
    猜你喜欢
    • 1970-01-01
    • 2020-07-14
    • 2017-11-03
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多