-
Notifications
You must be signed in to change notification settings - Fork 894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Day94:说一下React Hooks在平时开发中需要注意的问题和原因? #906
Comments
1)不要在循环,条件或嵌套函数中调用Hook,必须始终在React函数的顶层使用Hook 这是因为React需要利用调用顺序来正确更新相应的状态,以及调用相应的钩子函数。一旦在循环或条件分支语句中调用Hook,就容易导致调用顺序的不一致性,从而产生难以预料到的后果。 2)使用 使用push直接更改数组无法获取到新值,应该采用析构方式,但是在class里面不会有这个问题 代码示例 function Indicatorfilter() {
let [num,setNums] = useState([0,1,2,3])
const test = () => {
// 这里坑是直接采用push去更新num
// setNums(num)是无法更新num的
// 必须使用num = [...num ,1]
num.push(1)
// num = [...num ,1]
setNums(num)
}
return (
<div className='filter'>
<div onClick={test}>测试</div>
<div>
{num.map((item,index) => (
<div key={index}>{item}</div>
))}
</div>
</div>
)
}
class Indicatorfilter extends React.Component<any,any>{
constructor(props:any){
super(props)
this.state = {
nums:[1,2,3]
}
this.test = this.test.bind(this)
}
test(){
// class采用同样的方式是没有问题的
this.state.nums.push(1)
this.setState({
nums: this.state.nums
})
}
render(){
let {nums} = this.state
return(
<div>
<div onClick={this.test}>测试</div>
<div>
{nums.map((item:any,index:number) => (
<div key={index}>{item}</div>
))}
</div>
</div>
)
}
} 3)useState设置状态的时候,只有第一次生效,后期需要更新状态,必须通过useEffect 看下面的例子 TableDeail是一个公共组件,在调用它的父组件里面,我们通过set改变columns的值,以为传递给TableDeail的columns是最新的值,所以tabColumn每次也是最新的值,但是实际tabColumn是最开始的值,不会随着columns的更新而更新 const TableDeail = ({
columns,
}:TableData) => {
const [tabColumn, setTabColumn] = useState(columns)
}
// 正确的做法是通过useEffect改变这个值
const TableDeail = ({
columns,
}:TableData) => {
const [tabColumn, setTabColumn] = useState(columns)
useEffect(() =>{setTabColumn(columns)},[columns])
} 4)善用useCallback 父组件传递给子组件事件句柄时,如果我们没有任何参数变动可能会选用useMemo。但是每一次父组件渲染子组件即使没变化也会跟着渲染一次。 5)不要滥用useContext 可以使用基于useContext封装的状态管理工具。 |
|
// 简单实现hooks
// 一、实现useState
const { render } = require("react-dom");
let memoriedStates = [];
let lastIndex = 0;
function useState(initialState) {
memoriedStates[lastIndex] = memoriedStates[lastIndex] || initialState;
function setState(newState) {
memoriedStates[lastIndex] = newState;
// 状态更新完毕,调用render函数。重新更新视图
render();
}
// 返回最新状态和更新函数,注意index要前进
return [memoriedStates[lastIndex++], setState];
}
// 二、实现useEffect
let lastDendencies; // 存放依赖项的数组
function useEffect(callback, dependencies) {
if (lastDendencies) {
// 判断传入的依赖项是不是都没有变化,只要有以一项改变,就需要执行callback
const isChange = dependencies && dependencies.some((dep, index) => dep !== lastDendencies[index]);
if (isChange) {
// 一开始没有值,需要更新一次(相当于componentDidMount)
typeof callback === 'function' && callback();
// 更新依赖项
lastDendencies = dependencies;
}
} else {
// 一开始没有值,需要更新一次(相当于componentDidMount)
typeof callback === 'function' && callback();
// 更新依赖项
lastDendencies = dependencies;
}
}
// 三、实现useCallback
let lastCallback; // 最新的回调函数
let lastCallbackDependencies = []; // 回调函数的依赖项
function useCallback(callback, dependencies = []) {
if (lastCallback) {
const isChange = dependencies && dependencies.some((dep, index) = dep !== lastCallbackDependencies[index]);
if (isChange) {
// 只要有一个依赖项改变了,就更新回调(重新创建)
lastCallback = callback;
lastCallbackDependencies = dependencies;
}
} else {
lastCallback = callback;
lastCallbackDependencies = dependencies;
}
// 最后需要返回最新的函数
return lastCallback;
}
// 四、实现useRef
let lastRef;
function useRef(initialValue = null){
lastRef = lastRef != undefined ? lastRef : initialValue;
// 本质上就是返回一个对象,对象种有一个current属性,值为初始化传入的值,如果没有传入初始值,则默认为null
return {
current: lastRef
}
}
// 五、实现useContext
function useContext(context){
// 很简单,就是返回context的_currentValue值
return context._currentValue;
}
// 六、实现useReducer
let lastState;
function useReducer(reducer, initialState){
lastState = lastState !== undefined ? lastState : initialState;
// dispatch一个action,内部就是自动调用reducer来计算新的值返回
function dispatch(action){
lastState = reducer(lastState, action);
// 更新完毕后,需要重新渲染视图
render();
}
// 最后返回一个的状态值和派发action的方法
return [lastState, dispatch];
} |
1.useState, 为啥index要前进?0不行吗 |
|
useState 不会自动合并状态,并且不推荐直接用state来改变下次状态 |
No description provided.
The text was updated successfully, but these errors were encountered: