1. 使用之前的状态设置状态是不可预测的
状态管理是 React 的基础,虽然useState
可能是最常见的钩子,但可能对其实际行为有些不了解。
让我们来看看以下组件:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [counter, setCounter] = useState(0);
return (
<div className="App">
<h1>Counter: {counter}</h1>
<button
onClick={() => {
setCounter(counter + 1);
setCounter(counter + 1);
}}
>
+
</button>
</div>
);
}
在用户单击按钮后,您希望计数器状态的值是多少? A. 2 B. 1 ✔️
点击demo
原因是在我们的状态更新期间,我们使用了之前的状态值:setCounter(count + 1)。本质上,setState函数被包装在功能组件闭包中,因此它提供了在该闭包中捕获的值
。这意味着当它最终被执行时(setState函数是异步的),它可能持有一个不再相关的状态值。最重要的是,setState 的连续执行可能会导致 React 的调度算法使用相同的事件处理程序处理多个非常快速的状态更新。
在异步函数中设置状态时也可能出现同样的问题:
onClick={() => {
setTimout(() => { setCounter(counter + 1); ), 1000);
}};
但是,不用担心,React 实际上为这个问题提供了一个简单的解决方案——“functional updates”。
setCounter((prevCounter) => prevCounter + 1);
// incorrect
const update = useCallback(() => {
setCounter(counter + 1);
}, [counter]);
// correct ✔️
const update = useCallback(() => {
setCounter(prevCounter => prevCounter + 1);
}, []);
2.可以使用useRef来存储静态变量
我们习惯于使用 React 中的 ref 机制作为访问元素的 DOM 节点的手段,无论是因为我们需要它来计算其大小、设置焦点状态,或者基本上做任何 React 自然不能做的事情。但是 refs 也可以用于不同的目的——我们可以使用类组件非常容易·实现这一点,但我们不能使用函数式组件——保留一个不会在每次渲染时重新创建的静态变量
。
点击demo
3. React 可以强制重新挂载一个组件
写入DOM的成本非常高。这就是为什么我们通常不想重新mount 组件,除非绝对必要。但是有时我们必须,出于各种原因。那么在那种情况下,我们如何告诉 react 卸载并立即重新mount 组件?用一个简单的技巧——为我们的组件提供一个key,并改变它的值。
著名的 React 警告
key是帮助 React 跟踪元素的东西,即使我们已经改变了它在组件结构中的位置或重新渲染了父级(否则每次渲染都会导致整个组件数组被重新安装,这是不好的性能
)。
使用这种机制,我们可以欺骗 React 认为一个组件与其之前的自己不同,并导致它重新挂载。
点击demo
import React, { useEffect, useState, useCallback } from "react";
import "./styles.css";
export default function App() {
const [key, setKey] = useState(1);
const [console, setConsole] = useState([]);
const onLifecycleChange = useCallback((message) => {
setConsole((prevConsole) => [message, ...prevConsole]);
}, []);
return (
<div className="App">
<button
onClick={() => {
setKey((oldKey) => oldKey + 1);
}}
>
Remount
</button>
<ChildComp key={key} onLifecycleChange={onLifecycleChange} />
<div className="console">
{console.map((text, i) => (
<div key={i}>{text}</div>
))}
</div>
</div>
);
}
const ChildComp = React.memo(({ onLifecycleChange }) => {
useEffect(() => {
onLifecycleChange("mounting ChildComp");
return () => {
onLifecycleChange("ummounting ChildComp");
};
}, [onLifecycleChange]);
return <div style={{ marginTop: 10 }}>Child Comp</div>;
});
4.Context不像你期望的那样工作
-
use-context-selector可以解决context带来的性能问题
-
频繁更新状态(状态共享)的,推荐使用Redux等状态管理工具
import React, { useState, useContext } from "react";
import "./styles.css";
const SomeContext = React.createContext({});
export default function App() {
const [contextValue, setContextValue] = useState({ name: "John", age: 55 });
const onChangeAge = (e) => {
const age = e.target.value;
setContextValue((prevContextValue) => ({ ...prevContextValue, age }));
};
const onChangeName = (e) => {
const name = e.target.value;
setContextValue((prevContextValue) => ({ ...prevContextValue, name }));
};
return (
<div className="App">
<SomeContext.Provider value={contextValue}>
<Wrapper />
<input value={contextValue.age} onChange={onChangeAge} />
<input value={contextValue.name} onChange={onChangeName} />
</SomeContext.Provider>
</div>
);
}
const Wrapper = () => {
return (
<div>
<Name />
<Age />
</div>
);
};
const Name = () => {
const { name } = useContext(SomeContext);
console.log("name rendered");
return <h1>Name: {name}</h1>;
};
const Age = () => {
const { age } = useContext(SomeContext);
console.log("age rendered");
return <h1>Age: {age}</h1>;
};
点击demo
5. React 有一个完整的 API 来处理 children 属性
React.Children.toArray(children)
// If you want to use map/forEach:
React.Children.map(children, fn)
React.Children.forEach(children, fn)
React.Children.count(children)
React.Children.only(children)
import React from "react";
import "./styles.css";
export default function App() {
return (
<div className="App">
<Wrapper>
<h2 style={{ color: "red", margin: 0 }}>Red</h2>
<h2 style={{ color: "blue" }}>Blue</h2>
<h2 style={{ color: "green" }}>Green</h2>
</Wrapper>
<Wrapper>hello</Wrapper>
</div>
);
}
const Wrapper = ({ children }) => {
const childrenArray = React.Children.toArray(children);
console.log(childrenArray);
return (
<div style={{ border: "1px solid", padding: 20, margin: 5 }}>
<div>{children}</div>
<div>Number of children: {React.Children.count(children)}</div>
<div>
children type: <strong>{typeof children}</strong>
</div>
</div>
);
};
点击demo
参考文献
- medium.com/geekculture…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!