useState 第一个值用来取值, 第二个值为一个方法,用来赋值和更新视图
import React, {
useState } from 'react';
const Hooks = (): any => {
const [msg, setMsg] = useState<string>('啥也be是');
const Click = (): void => {
setMsg(Math.random().toString())
}
return (
<>
<p onClick={
() => Click()}>{
msg }</p>
</>
)
}
export default Hooks
有时候,我们只想在 React 更新 DOM 之后运行一些额外的代码。比如发送网络请求,手动变更 DOM,记录日志,这些都是常见的无需清除的操作。因为我们在执行完这些操作之后,就可以忽略他们了。
import React, {
useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${
count} times`;
});
return (
<div>
<p>You clicked {
count} times</p>
<button onClick={
() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。
为什么在组件内部调用 useEffect? 将 useEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)。我们不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。
useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。(我们稍后会谈到如何控制它。)你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。
清除副作用
你可能认为需要单独的 effect 来执行清除操作。但由于添加和删除订阅的代码的紧密性,所以 useEffect 的设计是在同一个地方执行。如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它:
import React, {
useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
为什么要在 effect 中返回一个函数? 这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。
React 何时清除 effect? React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
尽可能使用标准的 useEffect 以避免阻塞视觉更新。
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的
context 值由上层组件中距离当前组件最近的
当组件上层最近的
调用了 useContext 的组件总会在 context 值变化时重新渲染。如果重渲染组件的开销较大,你可以 通过使用 memoization 来优化。
import React, {
useState, useContext } from 'react';
interface listType {
name: string
}
let ThemeContext: any = null
const Hooks = (): any => {
const [list, setList] = useState<Array<listType>>([
{
name: 'this is a hook'
},
{
name: '张无忌'
},
{
name: '梓曦'
},
]);
ThemeContext = React.createContext(list);
const Click = (): void => {
let arr: Array<listType> = JSON.parse(JSON.stringify(list))
arr.push({
name: '什么也不是' })
setList(arr)
}
return (
<>
<p onClick={
() => Click()}>改变他</p>
<ul>
{
list.map((item: listType, index: number) => {
return(
<li key={
index}>{
item.name }</li>
)
})
}
</ul>
<ThemeContext.Provider value={
list}>
<Toolbar></Toolbar>
</ThemeContext.Provider>
</>
)
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
let list: any = useContext(ThemeContext);
return (
<ul>
{
list.map((item: listType, index: number) => {
return(
<li key={
index}>{
item.name }</li>
)
})
}
</ul>
);
}
export default Hooks
useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。
import React, {
useReducer } from 'react';
const stateObj: any = {
msg: '什么也be是'
}
const reducer = (state: any, action: any): any => {
switch (action.type) {
case 'ALTER':
state.msg = action.info
return {
...state }
default:
return state
}
}
const Hooks = (): any => {
const [state, dispatch] = useReducer(reducer, stateObj)
const Click = (): void => {
dispatch({
type: 'ALTER', info: '我要替换你' })
}
return (
<>
<p>{
state.msg }</p>
<p onClick={
() => Click()} style={
{
cursor: 'pointer'}}>alter</p>
<Element dispatch={
dispatch}></Element>
</>
)
}
const Element = (props: any): any => {
const Click = (): void => {
props.dispatch({
type: 'ALTER', info: '我是组件二' })
}
return (
<>
<p onClick={
() => Click()} style={
{
cursor: 'pointer'}}>组件二</p>
</>
)
}
export default Hooks
import React, {
useState, useCallback } from 'react';
const Hooks = (): any => {
const [msg, setMsg] = useState<string>('啥也be是');
const callback = useCallback((): string => {
return msg
}, [msg])
const Click = (): void => {
setMsg(Math.random().toString())
}
return (
<>
<p onClick={
() => Click()} className="banOnSelected">{
callback() }</p>
</>
)
}
export default Hooks
import React, {
useState, useCallback, useMemo } from 'react';
const Hooks = (): any => {
const [msg, setMsg] = useState<string>('啥也be是');
const [state, setState] = useState<string>('useState');
const callback = useCallback((): string => {
return msg
}, [msg])
const memo = useMemo(() => {
return state
}, [state])
const Click = (): void => {
setState(state + '=-=')
setMsg(Math.random().toString())
}
return (
<>
<p onClick={
() => Click()} className="banOnSelected">{
callback() }</p>
<p onClick={
() => Click()} className="banOnSelected">{
memo }</p>
</>
)
}
export default Hooks
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref对象在组件的整个生命周期内保持不变。
本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。
你应该熟悉 ref 这一种访问 DOM 的主要方式。如果你将 ref 对象以
然而,useRef() 比 ref 属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。
这是因为它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: …} 对象的 唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。
请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。
用来操作元素时
import React, {
useRef } from 'react';
const Hooks = (): any => {
const div = useRef<any>(null)
const divClick = (): void => {
if(div && div.current) {
div.current.style.color = 'skyblue'
}
}
return (
<>
<div onClick={
() => divClick()} ref={
div}>this is a div</div>
</>
)
}
export default Hooks
还可以用来当state时
import React, {
useRef } from 'react';
const Hooks = (): any => {
const state = useRef<any>(['一', '二', '三', '四', '五', '六', '七'])
const [ msg, setMsg ] = useState<string>('')
const divClick = (): void => {
console.log(state.current) //['一', '二', '三', '四', '五', '六', '七']
state.current.pop()
console.log(state.current) //['一', '二', '三', '四', '五', '六']
//但此时视图是不会更新的,如果想要视图更新,需使用一个useState的setState方法
//eg: setMsg('什么也be是'),此时视图才会更新
}
return (
<>
<div onClick={
() => divClick()} ref={
div}>this is a div</div>
</>
)
}
export default Hooks