React-如何强制功能组件渲染?


84

我有一个功能组件,我想强迫它重新渲染。

我该怎么办?
由于没有实例this,因此我无法致电this.forceUpdate()


不,无状态组件没有状态。请改用课程
TryingToImprove

2
您真的是“无状态组件”而不是“功能组件”吗?
克里斯(Chris

2
为了更新无状态组件,传入的道具需要更改。
fungusanthrax

在道具旁边,您可以使用hook useState,并且当更改时组件将被重新渲染
Hamid Shoja

Answers:


134

now您现在可以使用React挂钩

现在,使用react挂钩,您可以调用useState()函数组件。

useState()将返回由2个元素组成的数组:
1.一个值,表示当前状态。
2.它的二传手。用它来更新值。

通过其设置程序更新值将迫使您的功能组件重新呈现
就像这样forceUpdate做:

import React, { useState } from 'react';

//create your forceUpdate hook
function useForceUpdate(){
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => ++value); // update the state to force render
}

function MyComponent() {
    // call your hook here
    const forceUpdate = useForceUpdate();

    return (
        <div>
            {/*Clicking on the button will force to re-render like force update does */}
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

您可以在此处找到演示

上面的组件使用了自定义的钩子函数(useForceUpdate),该函数使用了布尔状态钩子(useState)。它切换布尔状态,从而告诉React重新运行render函数。

编辑

在此答案的旧版本中,代码段使用布尔值,并将其切换为forceUpdate()。现在,我已经编辑了答案,该代码段使用数字而不是布尔值。

为什么呢 (你会问我)

因为发生在我身上的forceUpdate()是,后来又从2个不同的事件中两次调用了my ,因此将布尔值重置为其原始状态,并且组件从未呈现。

因为在useState的setter(setValue此处)中,React将之前的状态与新的状态进行比较,并且仅在状态不同时才进行渲染。


3
该页面上没有任何有关使用Hooks进行调用的信息forceUpdate
jdelman '18

1
现在,这是对的,这是更好的,因为即使尚未发布强壮的钩子,您仍然可以在Beta中使用它。但是,一旦它们发布,没有理由说类组件会更好。使用钩子使代码比类组件更干净,如reactconf下面的视频所示。无论如何,问题是这是否可能。现在,由于有钩子,答案从“否”变为“是”。youtube.com/watch?v=wXLf18DsV-I
Yairopro

1
嗨@DanteTheSmith。如您所说,“顶层”表示不得从条件或循环内部调用挂钩。但是我可以告诉您,您可以从另一个函数内部调用它们。这意味着创建一个自定义钩子。丹·阿布拉莫夫(Dan Abramov)在React conf中展示React钩子时,清楚地表明这是在功能组件之间共享逻辑的最干净,最好的方法:youtu.be/dpw9EHDh2bM?
t=2753

1
无需切换任何状态“强制渲染”。您会产生一个错误的印象,即React会“比较”上一个和下一个状态值,以决定是否需要重新渲染。虽然绝对没有。
卑鄙的

1
@meandre是的,绝对可以比较。我们在谈论的是useState钩子,而不是类,setState它实际上并不能进行比较(除非您实现了shouldUpdate方法)。看到我发布的同一演示,但是使用的静态值setState,它不会再次呈现:codesandbox.io/s/determined-rubin-8598l
Yairopro19年

47

更新react v16.8(2019年2月16日实现)

由于使用钩子发布了react 16.8,因此功能组件现在可以保持持久性state。有了这种能力,你现在可以模仿一个forceUpdate

请注意,应该重新考虑这种方法,并且在大多数情况下,当您需要强制执行更新时,您可能做错了什么。


反应之前16.8.0

不行,State-Less函数组件只是functions返回的正常对象jsx,您没有访问React生命周期方法的权限,因为您没有从扩展React.Component

将功能组件视为render类组件的方法部分。


可以的。更改涉及到它的道具
玛丽安泽科Šedaj

5
这不是强制重新渲染,而只是普通渲染。当您想强制渲染时,通常是您希望在未设计为要运行的情况下运行render方法,例如在没有新内容propsstate更改的情况下。您无法强制渲染功能,因为render无状态组件上没有功能。无状态组件并非extends React.Component仅仅是返回的简单函数jsx
Sagiv bg

关于“当您需要强制执行更新时您可能正在做错事情”的提议-我知道是这种情况,但这只是促使我对useEffect挂钩进行了更好的了解。
卫理公会

12

现在,如果您确实需要这样做,则官方常见问题解答(https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate)建议采用这种方式:

  const [ignored, forceUpdate] = useReducer(x => x + 1, 0);

  function handleClick() {
    forceUpdate();
  }

好吧,我从来不知道
Charith Jayasanka

9
您可以将代码缩短7个字节,并且不要创建未使用的变量:const [, forceUpdate] = useReducer(x => x + 1, 0);
Konstantin Smolyanin

7

我使用了一个名为use-force-update的第三方库 来强制渲染我的React功能组件。像魅力一样工作。只需在项目中使用import包并使用即可。

import useForceUpdate from 'use-force-update';

const MyButton = () => {

  const forceUpdate = useForceUpdate();

  const handleClick = () => {
    alert('I will re-render now.');
    forceUpdate();
  };

  return <button onClick={handleClick} />;
};

2
为了节省您的点击时间-useForceUpdate使用useCallback其他答案中提到的方法。该库只是一个实用程序库,可以节省一些击键。
asyncwait

哦谢谢。我不知道 :)
Charith Jayasanka

6

免责声明:并非问题的答案。

在此处留下重要说明:

如果您试图强制更新无状态组件,则可能是您的设计有问题。

考虑以下情况:

  1. 将setter(setState)传递给可以更改状态并导致父组件重新呈现的子组件。
  2. 考虑提升状态
  3. 考虑将该状态放入Redux存储中,这可以自动在连接的组件上强制重新渲染。

1
我有一种情况,我需要禁用组件更新并在需要时强制进行更新(是移动的标尺,它会在每次移动时更新其值,并且更新导致闪烁的行为)。因此,我决定在此组件上使用类,并且我建议所有需要对呈现行为进行深度控制的组件都应在类中完成,因为当前的钩子无法很好地控制此行为。(当前的React版本是16.12)
Michael Wallace

我也这么认为,但是,我想要快速解决问题,所以我使用了强制更新。
Charith Jayasanka

在现实世界中,它有用途。没有什么是完美的,而且,如果您想让软件脱颖而出,那么您最好知道如何在别人搞砸软件时使事情成真。
Brain2000

1

无需显式使用钩子即可完成此操作,前提是您向组件添加了prop,向无状态组件的父组件添加了状态:

const ParentComponent = props => {
  const [updateNow, setUpdateNow] = useState(true)

  const updateFunc = () => {
    setUpdateNow(!updateNow)
  }

  const MyComponent = props => {
    return (<div> .... </div>)
  }

  const MyButtonComponent = props => {
    return (<div> <input type="button" onClick={props.updateFunc} />.... </div>)
  }

  return (
    <div> 
      <MyComponent updateMe={updateNow} />
      <MyButtonComponent updateFunc={updateFunc}/>
    </div>
  )
}

1

接受的答案是好的。只是为了使其更容易理解。

示例组件:

export default function MyComponent(props) {

    const [updateView, setUpdateView] = useState(0);

    return (
        <>
            <span style={{ display: "none" }}>{updateView}</span>
        </>
    );
}

要强制重新渲染,请调用以下代码:

setUpdateView((updateView) => ++updateView);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.