【问题标题】:Calling setState without triggering re-render在不触发重新渲染的情况下调用 setState
【发布时间】:2018-03-27 21:02:49
【问题描述】:

我将 UI 状态存储在 React 组件的 state 中,例如 this.state.receivedElements,它是一个数组。每当一个元素被推送到receivedElements 时,我都想重新渲染。我的问题是,当数组为空时,我可以不触发渲染吗?
或者一般来说,我可以只调用一次setState() 而不重新渲染,而其他时间都重新渲染吗? (有什么选择,解决方法吗?)
我已经阅读了这个帖子:https://github.com/facebook/react/issues/8598,但没有找到任何东西。

【问题讨论】:

  • 听起来你想破解你的组件的行为。你认为,在你需要破解黑客之前,它会持续多久?你为什么不解释一下你正在构建什么以及你有什么问题。或者换句话说,是什么实际问题导致了您正在尝试的这种 hack。
  • 实际上,我并不是要hack..我只是想知道我是否可以避免不必要的渲染...即使发生渲染也不会出错:)
  • 这应该通过 shouldComponentUpdate() 来解决。

标签: javascript reactjs


【解决方案1】:

每当一个元素被推送到receivedElements时,我都想重新渲染。

请注意,如果您使用,不会重新渲染:

this.state.receivedElements.push(newElement); // WRONG

这违反了你不能直接修改状态的限制。你需要:

this.setState(function(state) {
    return {receivedElements: state.receivedElements.concat([newElement])};
});

(它需要是回调版本,因为它依赖于当前状态来设置新状态。)

我的问题是,当数组为空时,我可以不触发渲染吗?

是的——在这种情况下不调用setState

听起来好像receivedElements 不应该是您的状态的一部分,而是您单独管理的信息并在state 中适当地反映。例如,您可能在组件本身上有receivedElements,在state 上有displayedElements。那么:

this.receivedElements.push(newElement);
this.setState({displayedElements: this.receivedElements.slice()});

...和

// (...some operation that removes from `receivedElements`...), then:
if (this.receivedElements.length) {
    this.setState({displayedElements: this.receivedElements.slice()});
}

注意如果this.receivedElements 为空,我们不会调用setState

【讨论】:

  • 虽然此解决方案有效且不会调用新渲染,但我强烈建议不要直接修改状态并每次都使用 setState()。如果由于某种原因你不想在 state 改变后调用 render,你应该使用 shouldComponentUpdate
  • @patotoma:我不同意应该避免上述情况;如果有时不应呈现对元素的更改,那么在我看来,它们不应成为state 的一部分。不过,shouldComponentUpdate 是另一种可行的方法;你可能会发布一个答案。
  • @T.J.Crowder 非常解释!谢谢!!我已经知道“变异状态不会导致渲染”和“它需要是回调版本”,但现在我对在 state 中存储什么以及不应该存储什么有了全新的看法:)
  • @patotoma:我知道使用shouldComponentUpdate.. 看来你不明白我在这里问的(愚蠢的?)问题.. 我只是想知道我是否可以跳过一次渲染,或者,如果我可以调用 setState 而不实际触发一次重新渲染。
【解决方案2】:

useRef 呢?

文档说: useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数 (initialValue)。返回的对象将在组件的整个生命周期内持续存在。

因此,如果您在 useEffect 中更改 ref 值,它不会重新渲染组件。

  const someValue = useRef(0)
  useEffect(() => {
    someValue.current++
  },[])

【讨论】:

【解决方案3】:

useState 返回一对 - 一个包含两个元素的数组。第一个元素是当前值,第二个元素是允许我们更新它的函数。如果我们更新当前值,则不会调用渲染。如果我们使用函数,则调用渲染。

const stateVariable = React.useState("value");

stateVariable[0]="newValue"; //update without rendering
stateVariable[1]("newValue");//update with rendering

对象

如果一个状态变量被声明为一个对象,那么我们可以改变它的第一个元素。在这种情况下,不会调用渲染。

const [myVariable, setMyVariable] = React.useState({ key1: "value" });

myVariable.key1 = "newValue"; //update without rendering
setMyVariable({ key1:"newValue"}); //update with rendering

数组

如果一个状态变量被声明为一个数组,那么我们可以改变它的第一个元素。在这种情况下,不会调用渲染。

const [myVariable, setMyVariable] = React.useState(["value"]);

myVariable[0] = "newValue"; //update without rendering
setMyVariable(["newValue"]); //update with rendering

link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    • 2021-12-27
    • 1970-01-01
    • 2016-09-09
    相关资源
    最近更新 更多