记录一下学习过程中的笔记,也便于自己查看
Hooks 能够在无需编写类的情况下使用状态和其他 React 特性 例如-组件的状态
你可以使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用。
什么是hook?
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。
useState Hook
useState用于管理页面中的状态,返回当前状态和改变当前状态的方法,可以说是最常用的hook。
场景 当你需要向函数式组件向其添加一些state,并对其进行管理
import React {useState} from 'react';
function example(){
const [count, setCount] = useState(0);
return (
<div>
<span>{count}</span>
<button onClick={()=>setCount(count+1)>
</div>
)
}
以上例子引入useState用于管理组件的内部state
组件通过调用 useState Hook 声明了一个新的 state 变量。它返回一对值给到我们命名的变量上。我们把变量命名为 count,它存储的是点击次数。我们通过传入一个值 0 作为 useState 唯一的参数来将其初始化为 0。第二个返回的值是一个setState函数,这个函数可以更新 count 的值.
useEffect Hook
useEffect能够在组件中执行副作用
useEffect 的执行时机 在组件 mount 和 unmount 以及每次重新渲染的时候执行,也就是会在 componentDidMount、componentDidUpdate、componentWillUnmount 这三个时期执行。
effect分为需要清除的不用清除两种
清理函数(clean up)什么时候执行? 它会在前一次 effect执行后,下一次 effect 将要执行前,以及 Unmount 时期执行
使用场景
无需清除的Effect
*发送网络请求
*监听页面大小变化
function getSize() {
return {
innerHeight: window.innerHeight,
innerWidth: window.innerWidth,
outerHeight: window.outerHeight,
outerWidth: window.outerWidth
};
}
function useWindowSize() {
let [windowSize, setWindowSize] = useState(getSize());
function handleResize() {
setWindowSize(getSize());
}
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return windowSize;
}
const windowSize = useWindowSize();
return <div>页面高度:{windowSize.innerWidth}</div>;
需要清除的Effect
*订阅外部数据源
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
// 清除订阅
subscription.unsubscribe();
};
});
其中useEffect中返回了一个函数,用于清除Effect。
React会在组件卸载的时候执行清除操作。
useEffect 会在每次渲染结束后执行,但也可以选择让它在只有某些值改变的时候才执行。下述例子在props.source改变时才会执行。
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
UseContext
用来处理多层级传递数据的方式。在一些组件中,跨层级祖先组件想要给孙子组件传递数据的时候,除了将props一层层往下传到孙子组件的方法之外,还可以使用useContext。
利用React.createContext创建一个context对象
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
}
const ThemeContext = React.createContext(themes.light);
使用Context.Provider提供了一个Context对象,这个对象可以被所有子组件共享
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
子组件利用useContext来获取Context对象,并且获取到它的值。
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
useReducer
useState能够管理组件的一些状态,但是当state逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 的情况时利用useReducer更为适用。
基本用法
const [state, dispatch] = useReducer(reducer, initialArg, init);
其中useReducer的参数为一个reducer函数和一个状态的初始值,并且返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送 action 的dispatch函数。
其中reducer函数的参数为当前的状态和action.
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
以上例子可以看到dispatch 的参数是 reducer 的 action,reducer 函数根据传入的 action 执行某些逻辑,最后返回的就是新状态。
useRef
应用场景
1、保存可变的值
2、访问DOM
场景1、保存可变的值
useRef接收一个参数作为初始值,并返回一个引用,该引用有一个特殊的属性current.
利用reference.current 能够获取到引用的值,
reference.current = newValue 能够更新reference的值。
import { useRef } from 'react';
function MyComponent() {
const reference = useRef(initialValue);
const someHandler = () => {
// Access reference value:
const value = reference.current;
// Update reference value:
reference.current = newValue;
};
}
值得注意的是,在组件重新渲染后reference.current的值不会改变 ;
并且当 reference.current的值改变后不会触发组件的更新。
场景2、访问dom 元素,可获取被标识元素的属性。
import { useRef, useEffect } from 'react';
function InputFocus() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<input
ref={inputRef}
type="text"
/>
);
}
自定义hook
将上述介绍的hooks封装起来可以变成一个自定义的钩子
所有的钩子都是为函数引入外部功能,所以 React 约定,钩子一律使用use前缀命名,便于识别。所以当你定义自己的hook时需要将钩子函数命名为usexxxx.
const usePerson = (personId) => {
const [loading, setLoading] = useState(true);
const [person, setPerson] = useState({});
useEffect(() => {
setLoading(true);
fetch(`https://swapi.co/api/people/${personId}/`)
.then(response => response.json())
.then(data => {
setPerson(data);
setLoading(false);
});
}, [personId]);
return [loading, person];
};
其中usePerson就是自定义的一个hook。
在person组件使用usePerson。
const Person = ({ personId }) => {
const [loading, person] = usePerson(personId);
if (loading === true) {
return <p>Loading ...</p>;
}
return (
<div>
<p>You're viewing: {person.name}</p>
<p>Height: {person.height}</p>
<p>Mass: {person.mass}</p>
</div>
);
};
###参考链接
https://dmitripavlutin.com/react-useref-guide/
https://www.geeksforgeeks.org/reactjs-usereducer-hook/