hooks注意事项
- hooks不能再class组件中使用
- 只能在最外层调用hooks,不能再循环,判断,子函数中调用
- 只能在react的函数组件中调用hooks
useState
状态值
const [count,setCount] = useState(0); // 0 初始值
const [person, setPerson] = useState({
name: 'zs',
age: 19
})
// 1. state更新第一种方式
setCount(count + 1);
// 2. 函数式更新
setCount(() => count + 1);
// 3. 引用类型更新 使用扩展符形式
setCount({...person,name:20})
// 4. 如果数据没有更新,则页面不会发生渲染
useEffect
集合了几个的生命周期,不能放到if中。
useEffect(() => {
console.log('component did mount'); // componentDidMount
return () => {
console.log('component will unmount'); // componentWillUnmount
}
return null;
})
useEffect(() => {
console.log("hello"); // componentWillReceiveProps
},[props.value,props.next]) // 只要有任意一个属性改变,就会执行
useRef
import { useRef, useImperativeHandle, forwardRef } from "react";
// forwardRef 函数式组件不运行将ref作为props进行传递给子组件
const Child = forwardRef((props: {}, ref: any) => {
const inputRef = useRef<any>();
// useImperativeHandle:减少 子组件暴露的内容
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
}));
return (
<>
<input type="text" ref={inputRef} />
</>
);
});
export default function Parent() {
const childRef = useRef<any>();
const handleClick = () => {
childRef.current.focus();
};
return (
<div>
<p>RefComponent</p>
<button onClick={handleClick}>聚焦</button>
<Child ref={childRef} />
</div>
);
}
useContext
useContext只能声明在函数式组件内部。
// 顶层组件
import { createContext } from "react";
import Middle from "./MiddleComponent";
const theme = {
light: "#fff",
dark: "#000",
background: "pink",
};
export const ThemeContext = createContext(theme);
function Context() {
return (
<ThemeContext.Provider value={theme}>
<Middle />
</ThemeContext.Provider>
);
}
export default Context;
// 中间组件
import Bottom from "./Bottom";
function Middle() {
return <Bottom />;
}
export default Middle;
// 底层组件
import { useContext } from "react";
import { ThemeContext } from ".";
function Bottom() {
const theme = useContext(ThemeContext);
return <div style={{ backgroundColor: theme.background }}>2232323</div>;
}
export default Bottom;
useLayoutEffect
与useEffect函数效果一样,不过useLayoutEffect是在更新后立即执行,而useEffect中间可能穿插许多其他的事情,所以一般是在useEffect出错的情况下再使用useLayoutEffect。
useReducer
父子组件的通信: 利用useReducer,useContext可以进行父子组件间的通信(useReducer可以操作父组件的内容,useContext可以获取父组件间的内容)
import { useReducer } from 'react';
// 第一个参数: reducer:处理更新的reducer,
// 第二个参数:initialArg: 状态初始值
// 第三个参数:init: 状态初始化函数 将第二个参数,作为init函数的参数,将返回的结果作为state的初始值
const [state,dispatch] = useReducer(reducer,initialArg,init);
// 父组件
import { useReducer } from "react";
import BottomReducer from "./BottomReducer";
function reducer(
state: { count: number },
action: { type: string; payload?: number }
) {
switch (action.type) {
case "increment":
return add(state, action.payload);
case "decrement":
return { count: state.count - 1 };
case "reset":
return init(action.payload as number);
default:
throw new Error();
}
}
interface reducerProp {
initialCount: number;
}
function init(initialCount: number) {
return { count: initialCount };
}
function add(state: { count: number }, payload = 1) {
return { count: state.count + payload };
}
export default function ReducerComponent({ initialCount }: reducerProp) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (
<div>
<p>{state.count}</p>
<button
onClick={() => {
dispatch({ type: "reset", payload: initialCount });
}}
>
reset
</button>
<button
onClick={() => {
dispatch({ type: "increment" });
}}
>
+
</button>
<button
onClick={() => {
dispatch({ type: "decrement" });
}}
>
-
</button>
<BottomReducer dispatch={dispatch} state={state} />
</div>
);
}
// 子组件
export default function BottomReducer({
dispatch,
state,
}: {
dispatch: React.Dispatch<{
type: string;
payload?: number | undefined;
}>;
state: { count: number };
}) {
const double = () => {
dispatch({ type: "increment", payload: 2 });
};
return (
<div>
<p>BottomReducer</p>
<p>{state.count}</p>
<button onClick={double}>+2</button>
</div>
);
}
useCallback
当依赖没有发生改变的时候,该函数也不会发生改变,主要用于性能优化(memo+useCallback)
Memo:当父组件传递给子组件的props不发生改变,则子组件不会进行渲染。
函数内部没有返回值
import { useState, useCallback, memo } from "react";
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
const childClick = useCallback(() => {}, []);
return (
<div>
<p>useCallback</p>
<p>{count}</p>
<button onClick={handleClick}>click</button>
<Child click={childClick} />
</div>
);
}
const Child = memo(function Child({ click }: { click: () => void }) {
console.log(click);
console.log("子组件被触发了");
return <></>;
});
export default Counter;
useMemo
传入的函数内部需要返回值,和useCallback的主要区别。
useMemo只能生命在函数式组件内部。
useMemo不但可以返回值,还能返回dom结构。
import { useState, useMemo } from "react";
function MemoComponent() {
const [a, setA] = useState(0);
const [b, setB] = useState(0);
const [c, setC] = useState(0);
const handleClick = (type: string) => {
if (type === "a") {
setA(a + 1);
} else if (type === "b") {
setB(b + 1);
} else {
return false;
}
};
const d = useMemo(() => {
return a + b;
}, [a, b]);
return (
<>
<p>a:{a}</p>
<p>b:{b}</p>
<p>d:{d}</p>
<button
onClick={() => {
handleClick("a");
}}
>
+a
</button>
<button
onClick={() => {
handleClick("b");
}}
>
+b
</button>
</>
);
}
export default MemoComponent;