React Hooks是什么?
首先
由于在公司内进行了React Hooks学习会,作为会议记录和产出,我将写一篇文章。
React Hooks 是什么?
React16.8引入了一项功能,使得函数组件能够使用状态管理和生命周期等功能。
React Hooks诞生的背景
在React中,有两种编写方式:类组件和函数组件。以下是一个使用类组件编写的代码示例,通过按钮来切换文本内容。
import React from "react";
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
isLogin: true
}
}
toggleLoginStatus = () => {
this.setState({isLogin: !this.state.isLogin});
}
render() {
return (
<>
{this.state.isLogin ? "ログイン中" : "ログアウト中"}
<button onClick={this.toggleLoginStatus}>toggle</button>
</>
)
}
}
export default Hoge
通过按下按钮来改变isLogin的状态,并进行文本的切换。
据说在一段时间前,使用类组件来编写代码是常见的做法。
原因是,类组件可以使用状态管理、生命周期等功能,而函数组件无法使用这些功能。
React Hooks的出现解决了这个问题。
有了React Hooks,函数组件可以使用状态管理和生命周期功能,并且可以编写具有高可读性的代码。
下面是一个使用函数组件编写的与之前示例相同的版本。
import { useState } from "react";
const Hoge = () => {
const [isLogin, setIsLogin] = useState(true);
const toggleLoginStatus = () => {
setIsLogin(isLogin => !isLogin);
}
return (
<>
{isLogin ? "ログイン中" : "ログアウト中"}
<button onClick={toggleLoginStatus}>toggle</button>
</>
);
}
export default Hoge
我想您可能会注意到,与类组件相比,可以更简洁地编写相同的处理过程。
介绍React Hooks
简单来说,我会介绍一下React Hooks。
使用状态
useState是用于保持状态的钩子,在React Hooks中是最常用的钩子。它可以用来保持各种不同的状态,例如数字、布尔值、映射等。以下是一个示例,当按钮被点击时计数会增加。
import { useState } from "react";
const Hoge = () => {
const [count, setCount] = useState(0);
const countUp = () => {
setCount(count => count + 1);
}
return (
<>
<p>今のカウント:{count}</p>
<button onClick={countUp}>
count up!
</button>
</>
);
}
export default Hoge
使用使用效果
useEffect是一個用於實現生命周期(在類組件中稱為componentDidMount和componentDidUpdate, componentWillUnmount)的鉤子,它可以在渲染時或狀態更新時運行useEffect內的副作用函數。
只想在首次渲染时执行处理。
在useEffect的第二个参数中传入一个空的依赖数组。
// レンダリングされた時にのみ実行(componentDidMount)
useEffect(() => {
console.log("component did mount");
}, []);
当需要在特定的状态被更新时执行处理时
在useEffect的第二个参数中指定要监视的状态。
// countが更新された時に実行(componentDidUpdate)
useEffect(() => {
console.log("component did update");
console.log(`current count is ${count}`);
}, [count])
关于组件的删除(卸载时)
通过在useEffect中返回函数,可以在组件卸载时删除执行的副作用函数。通过这样做可以避免意外的错误。返回的函数被称为清理函数。
// コンポーネントが削除される際に実行(componentWillUnmount)
useEffect(() => {
return () => {
console.log("component will unmount");
};
}, [])
这里是总结以上内容的一份文件。
import { useState, useEffect } from "react";
const Hoge = () => {
const [count, setCount] = useState(0);
const countUp = () => {
setCount(count => count + 1);
}
useEffect(() => {
console.log("component did mount");
}, []);
useEffect(() => {
console.log("component did update");
console.log(`current count is ${count}`);
}, [count])
useEffect(() => {
return () => {
console.log("component will unmount");
};
}, [])
return (
<>
今のカウント:{count}
<button onClick={countUp}>
count up!
</button>
</>
);
}
使用上下文
我想你可能会经常遇到需要从父组件向子组件传递值的情况,而有时也可能需要将值从父组件传递给孙子组件,具体情况而定。
在这种情况下,不需要通过父组件向子组件再向孙子组件传递props,可以使用useContext,这样就可以在任何层级上引用存储在Context中的值。
虽然这很方便,但需要注意的是,一旦更新了Context,使用该Context的所有组件都会重新渲染。
以下是在孙子组件中获取在父组件中定义的Context的代码。
import { useContext, createContext } from "react";
const user = {
name: "Taro",
age: 17
}
const UserContext = createContext(user);
const Hoge = () => {
return (
<UserContext.Provider value={user}>
<User />
</UserContext.Provider>
);
}
const User = () => {
return(
<UserProfile />
)
}
const UserProfile = () => {
const userInfo = useContext(UserContext);
return (
<>
<p>名前:{userInfo.name}</p>
<p>年齢:{userInfo.age}</p>
</>
);
}
export default Hoge
使用useReducer
useReducer跟useState一样,是一个用于管理状态的Hook,在需要根据多个值或条件来更新状态时主要使用。
它接收一个拥有(state, action) => newState类型的reducer函数,并返回当前状态和dispatch方法。
通过在onClick等事件中执行带有action作为参数的dispatch方法,reducer将被调用,并根据action来更新状态。
由于useReducer只返回newState,所以如果状态是以对象形式定义的,必须以对象的形式返回。
import { useReducer } from "react";
const reducer = (state: any, action: any) => {
switch (action) {
case "increment":
return { count: state.count + 1 }
case "decrement":
return { count: state.count - 1 }
default:
throw new Error();
}
}
const Hoge = () => {
const [countState, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
<p>今のカウント:{countState.count}</p>
<button onClick={() => dispatch("decrement")}>decrement</button>
<button onClick={() => dispatch("increment")}>increment</button>
</>
);
}
export default Hoge
使用useCallback
通过使用useCallback,可以将函数进行缓存,并以回调函数的形式返回,从而避免不必要的重新渲染。useCallback经常与React.memo一起使用。
React.memo 是什么?
React.memo是用于包装希望进行记忆化的组件的函数。记忆化是指如果props没有差异,则跳过重新渲染的过程,并记住上次渲染的组件结果。
然而,当作为prop接收回调函数时,即使使用了React.memo,组件仍会被重新渲染。这是因为即使函数内容相同,每次组件重新渲染时函数都会被重新创建,因此它们不会被视为与上一次相等。
因此,我们可以使用useCallback来对回调函数进行记忆化,以防止不必要的重新渲染。
下面是一个示例代码,演示了如何在使用React.memo进行了记忆化的组件中传递使用useCallback进行了记忆化的回调函数。
通过这种方式,当增加计数(更新状态)时,只会重新渲染被点击的组件。
import { React.memo, useCallback } from "react";
const Button = React.memo(({text, handleClick}) => {
// 確認用
console.log(text);
return (
<button onClick={handleClick}>{text}</button>
);
});
const Hoge = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const handleClick1 = useCallback(() => setCount1(count1 + 1), [count1]);
const handleClick2 = useCallback(() => setCount2(count2 + 1), [count2]);
return (
<>
<p>count1:{count1}</p>
<p>count2:{count2}</p>
<Button text={"count1:increment"} handleClick={handleClick1} />
<Button text={"count2:increment"} handleClick={handleClick2} />
</>
);
}
export default Hoge
使用 useMemo
useMemo是一个用于保存函数结果的钩子,通过避免不必要的重新计算,在重新渲染时可以提高性能。
上述的useCallback是对函数本身进行记忆化,而useMemo是对函数的结果进行记忆化。
以下是一个使用useMemo来保存计算结果,并在依赖的状态更新时才重新计算的代码示例。
import { useMemo } form "react";
const Hoge = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const twiceCount1 = useMemo(() => {
return 2 * count1;
}, [count1]);
const handleClick1 = () => setCount1(count1 => count1 + 1);
const handleClick2 = () => setCount2(count2 => count2 + 1);
return (
<>
<p>count1:{count1}</p>
<p>count2:{count2}</p>
<button onClick={handleClick1}>count1:increment</button>
<button onClick={handleClick2}>count2:increment</button>
<p>count1:{twiceCount1}</p>
</>
);
}
export default Hoge
使用useRef
useRef和useState一样,可以在组件中保存值。
与useState不同的是,当更新值时不会触发重新渲染。
因此,它通常用于处理与渲染无关的值的用例。
下面是使用例,展示了获取上一个状态的代码。※请参考官方文档
在绘制之后,可以使用useEffect来保持prevCount中的上一个状态,并在下次重新绘制时显示prevCount。
import { useRef } from "react";
const Hoge = () => {
const [count, setCount] = useState(0);
const prevCountRef = useRef(0);
useEffect(() => {
prevCountRef.current = count;
});
const prevCount = prevCountRef.current;
return (
<>
<p>今のカウント:{count}</p>
<p>前回のカウント:{prevCount}</p>
<button onClick={() => setCount(count+1)}></button>
</>
)
}
export default Hoge
总之
我简单地介绍了React Hooks的起源和官方Hooks。
我自己并没有很好地使用useCallback、useMemo和React.memo这些概念,通过这次记录我重新确认了这些基本概念。
我将努力在今后的开发和重构中编写性能优化的代码。