我有一个函数组件,我想强制它重新渲染。
我该怎么做呢? 因为没有实例this,所以我不能调用this. forceupdate()。
我有一个函数组件,我想强制它重新渲染。
我该怎么做呢? 因为没有实例this,所以我不能调用this. forceupdate()。
当前回答
如果你已经在函数组件中有一个状态,而你不想改变它并需要重新呈现,你可以伪造一个状态更新,这将反过来重新呈现组件
const [items,setItems] = useState({
name:'Your Name',
status: 'Idle'
})
const reRender = () =>{
setItems((state) => [...state])
}
这将保持状态不变,并将做出反应,认为状态已更新
其他回答
这些都没有给我一个满意的答案,所以最后我得到了我想要的关键道具,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)
}
}
公认的答案是好的。 只是为了更容易理解。
示例组件:
export default function MyComponent(props) {
const [updateView, setUpdateView] = useState(0);
return (
<>
<span style={{ display: "none" }}>{updateView}</span>
</>
);
}
强制重新渲染调用下面的代码:
setUpdateView((updateView) => ++updateView);
如果你已经在函数组件中有一个状态,而你不想改变它并需要重新呈现,你可以伪造一个状态更新,这将反过来重新呈现组件
const [items,setItems] = useState({
name:'Your Name',
status: 'Idle'
})
const reRender = () =>{
setItems((state) => [...state])
}
这将保持状态不变,并将做出反应,认为状态已更新
对我来说,仅仅更新状态是行不通的。我正在使用带有组件的库,看起来我不能强制组件更新。
我的方法是用条件渲染扩展上面的方法。在我的例子中,我想在值改变时调整组件的大小。
//hook to force updating the component on specific change
const useUpdateOnChange = (change: unknown): boolean => {
const [update, setUpdate] = useState(false);
useEffect(() => {
setUpdate(!update);
}, [change]);
useEffect(() => {
if (!update) setUpdate(true);
}, [update]);
return update;
};
const MyComponent = () => {
const [myState, setMyState] = useState();
const update = useUpdateOnChange(myState);
...
return (
<div>
... ...
{update && <LibraryComponent />}
</div>
);
};
您需要传递想要跟踪更改的值。钩子返回用于条件呈现的布尔值。
当更改值触发时,useEffect更新将变为false,从而隐藏组件。在此之后,第二个useEffect被触发,update变为true,这使得组件再次可见,并导致更新(在我的例子中是调整大小)。
官方常见问题现在推荐这种方式,如果你真的需要这样做:
const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
function handleClick() {
forceUpdate();
}