我可以在无状态组件中调用forceUpdate吗?

时间:2017-09-15 13:22:31

标签: javascript reactjs

我有一个无状态组件,我想重新渲染它。我怎么能这样做?我尝试使用forceUpdate,但它没有用。

我可以改为使用forUpdate吗?

11 个答案:

答案 0 :(得分:26)

您现在可以使用React hooks

使用反应挂钩,您现在可以在组件函数中调用useState()。这将返回由2个元素组成的数组:一个值和一个“ setter”函数,可用于更新返回的第一个值,这样做将迫使您的函数组件重新呈现,就像forceUpdate确实:

import React, { useState } from 'react';

//create your forceUpdate hook
function useForceUpdate(){
    const [value, set] = useState(true); //boolean state
    return () => set(!value); // toggle the state to force render
}

function MyComponent() {
    // use your hook her
    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>
    );
}

You can find a demo here

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

答案 1 :(得分:12)

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

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

  function handleClick() {
    forceUpdate();
  }

答案 2 :(得分:7)

不,你不能,State-Less组件只是返回functions的正常jsx,你没有任何访问React生命周期方法的权限,因为你没有从{{1}扩展{1}}。

答案 3 :(得分:7)

我使用了一个名为 use-force-update 强制渲染我的反应功能组件。像魅力一样工作。 只需在您的项目中使用导入包并像这样使用即可。

import useForceUpdate from 'use-force-update';

const MyButton = () => {

  const forceUpdate = useForceUpdate();

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

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

答案 4 :(得分:1)

这可以在不显式使用钩子的情况下完成,前提是您要向组件中添加道具并向无状态组件的父组件添加状态:

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>
  )
}

答案 5 :(得分:1)

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

示例组件:

export default function MyComponent(props) {

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

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

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

setUpdateView((updateView) => ++updateView);

答案 6 :(得分:0)

这些都没有给我一个满意的答案,所以最后我用 key 道具、useRef 和一些随机 id 生成器(如 shortid)得到了我想要的。

基本上,我希望某个聊天应用程序在有人第一次打开该应用程序时自行播放。因此,我需要通过异步等待的简便性来完全控制更新答案的时间和内容。

示例代码:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// ... your JSX functional component, import shortid somewhere

const [render, rerender] = useState(shortid.generate())

const messageList = useRef([
    new Message({id: 1, message: "Hi, let's get started!"})
])

useEffect(()=>{
    async function _ () {
      await sleep(500)
      messageList.current.push(new Message({id: 1, message: "What's your name?"}))
      // ... more stuff
      // now trigger the update
      rerender(shortid.generate())
   } 
   _()
}, [])

// only the component with the right render key will update itself, the others will stay as is and won't rerender.
return <div key={render}>{messageList.current}</div> 

事实上,这也让我可以滚动聊天消息之类的内容。

const waitChat = async (ms) => {
    let text = "."
    for (let i = 0; i < ms; i += 200) {
        if (messageList.current[messageList.current.length - 1].id === 100) {
            messageList.current = messageList.current.filter(({id}) => id !== 100)
        }
        messageList.current.push(new Message({
            id: 100,
            message: text
        }))
        if (text.length === 3) {
            text = "."
        } else {
            text += "."
        }
        rerender(shortid.generate())
        await sleep(200)
    }
    if (messageList.current[messageList.current.length - 1].id === 100) {
        messageList.current = messageList.current.filter(({id}) => id !== 100)
    }
}

答案 7 :(得分:0)

最佳方法 - 在每次渲染时不会重新创建多余的变量:

const forceUpdateReducer = (i) => i + 1

export const useForceUpdate = () => {
  const [, forceUpdate] = useReducer(forceUpdateReducer, 0)
  return forceUpdate
}

用法:

const forceUpdate = useForceUpdate()

forceUpdate()

答案 8 :(得分:0)

如果您使用版本 < 16.8 的功能组件。一种解决方法是直接调用相同的函数,如

import React from 'react';

function MyComponent() {
    const forceUpdate = MyComponent();
    
    return (
        <div>
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

但是如果你向它传递一些道具,这会中断。就我而言,我只是将收到的相同道具传递给重新渲染功能。

答案 9 :(得分:0)

你可以简单地这样做

如果您想启动重新渲染,请添加一个虚拟状态,您可以更改以启动重新渲染。

const [rerender, setRerender] = useState(false);

...
setRerender(!rerender);     //whenever you want to re-render

这将确保重新渲染,因为组件在状态更改时重新渲染

答案 10 :(得分:-2)

免责声明:不是问题的答案。

在此处留下重要说明:

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

请考虑以下情况:

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