useState
useState接受一个参数,该参数就是state初始化的数据,然后返回一个初始化state以及一个setState函数。
const [state, setState] = useState(initialState);
setstate可以接受一种数据或者一个函数。如果state是通过先前的state计算而来,那么就可以传入函数来设置state,这种方法官方叫做函数式更新。
函数式更新
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
惰性初始 state
如果初始化的state,需要通过复杂的计算得来,那么可以使用该特性。
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
useEffect
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
effect中的函数会在组件渲染到屏幕之后执行。
接受两个参数,一个参数是一个函数,return出去的函数会在组件卸载之前调用,第二个参数接受一个数组,表示只有在数组中的数据改变时才会重新生成effct函数。
useContext
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
类似vue的watch,
只有数组值发生改变,回调函数才会计算。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate
)的子组件时,它将非常有用。
useMemo
类似vue的computed 计算属性,只有当数组值发生改变才会重新计算数值。根据传入依赖项。
useRef
类似vue的ref,访问组件或者dom对象,通过ref,current
访问。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useImperativeHandle
useImperativeHandle
可以让你在使用 ref 时自定义暴露给父组件的实例值。useImperativeHandle
应当与forwardRef
一起使用:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
在本例中,渲染 <FancyInput ref={inputRef} />
的父组件可以调用 inputRef.current.focus()
。
父组件通过ref,通过forwardRef派发给子组件中的某个子元素,然后父组件就可以通过定义的ref,current,访问实例。
API:useImperativeHandle(ref, createHandle, [deps])
useLayoutEffect
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
尽可能使用标准的 useEffect 以避免阻塞视觉更新。
该Hook目前暂时不知道是干嘛用的,以后实战用到再深入理解。
useDebugValue
useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
// 在开发者工具中的这个 Hook 旁边显示标签
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}