react+typescript
类型简述
内置类型 | 说明 |
---|---|
React.ReactElement | 使用React.createElement 创建的,可以简单理解为React 中的JSX 的元素 |
React.ReactNode | <div>xxx</div> 的合法类型 |
React.CSSProperties | 组件内联的style 对象的类型 |
React.RefObject | React.createRef 创建的类型,只读不可改 |
React.MutableRefObject | useRef 创建的类型,可以修改 |
hooks 声明
useState
useState
可以使用泛型传参或者自动推断
const [state, setState] = useState(""); // state的类型为string,自动推断
const [state, setState] = useState<string>(); // state的类型为 string | undefined
// 给初值
const [state, setState] = useState<string | null>(null); // state的类型为 string | null
useEffect
当使用 useEffect
时,注意不要返回任何东西,除了函数或未定义:
function DelayedEffect(props: { timerMs: number }) {
const { timerMs } = props;
useEffect(
() =>
setTimeout(() => {
/* do stuff */
}, timerMs),
[timerMs]
);
return null;
}
useContext
useReducer
useReducer
相对来说要写的更多一点,可以自动推断,所以不需要手动写泛型类型
// state类型
interface ReducerState {
value: string;
}
// action类型
interface AnyAction {
type: string;
[key: string]: any;
}
// reducer函数
const reducer: React.Reducer<ReducerState, AnyAction> = (state, action) => {
switch (action.type) {
default:
return state;
}
};
// 初始值
const initialState: ReducerState = { value: "" };
const [state, dispatch] = useReducer(reducer, initialState);
// state 的类型为 ReducerState
// dispatch 的类型为 React.Dispatch<AnyAction>
Action
也可以是多个不同的Action
的联合类型
useCallback
useMemo
useRef
useRef
同样也会自动推断
const ref = useRef(""); // ref.current的类型为 string
// 泛型
type Value = { value: string };
const ref = useRef < Value > { value: "" };
// ref为html元素
const ref = useRef < HTMLDivElement > null;
return <div ref={ref} />;
需要注意的是如果ref
为元素,那么初始值得写个null
才不会报错
useImperativeHandle
useImperativeHandle
这个钩子可以把内部方法通过ref
暴露出去,用ts
也是要写多一点,类型都需要标注清楚
// props
interface AppProps {
value: string;
}
// useImperativeHandle获取到ref的类型
interface Handle {
get: () => string;
}
const App = React.forwardRef<Handle, AppProps>(({ value }, ref) => {
// 定义
useImperativeHandle(ref, () => ({
get: () => `handle get value : ${value}`,
}));
return null;
});
// 使用
const handleRef = useRef<Handle>(null);
// handleRef.current?.get();
return <App value="hello" ref={handleRef} />;
useLayoutEffect
useDebugValue
自定义 hooks
有如下钩子
const useCustomHook = () => {
const [state, setState] = useState("");
const set = (value: string) => {
if (!value) return;
setState(value);
};
return [state, set];
};
// 使用
const [state, setState] = useCustomHook();
setState("hello"); // This expression is not callabl
自定钩子还需要定义返回值才行
- const useCustomHook = () => {
+ const useCustomHook = (): [string, (value: string) => void] => {
组件声明
组件声明分为类组件和函数组件
类组件
类组件使用的定义主要为React.Component<P,S>
和React.PureComponent<P,S,SS>
interface AppProps {
value: string;
}
interface AppState {
count: number;
}
class App extends React.Component<AppProps, AppState> {
static defaultProps = {
value: "",
};
state = {
count: 0,
};
}
React.Component<P,S>
这里的P
是props
的类型,S
是state
的类型,可以写为React.Component<AppProp>
,因为state
的类型会自己推断
在上面PureComponent
中还有个SS
,这个SS
是getSnapshotBeforeUpdate
的返回值
函数组件
函数组件定义的方式简单来看有两种,一种是使用React.FC
,一种是直接给props
写上定义
interface AppProps {
value?: string;
}
const App: React.FC<AppProps> = ({ value = "", children }) => {
// ...
};
React.FC
的意思是FunctionComponent
,如果使用了React.FC
,它在定义里就已经规定好了children
的类型和函数的返回值,所以可以直接用children
,如果是直接给props
写上定义,就需要自己定义children
的类型
interface AppProps {
value?: string;
children?: React.ReactNode; // 自己定义children的类型
}
function App({ value = "", children }: AppProps) {
return <>{children}</>;
}
React.forwardRef
React.forwardRef<T, P = {}>
只需要传props
的类型和ref
的类型,第一个T
是ref
的类型,P
是props
的类型
const App = React.forwardRef<HTMLDivElement, AppProps>(({ value }, ref) => {
return <div ref={ref} />;
});
// 使用
const ref = useRef<HTMLDivElement>(null);
return <App value="hello" ref={ref} />;
React.ForwardRefRenderFunction
定义为该类型的函数可以放进React.forwardRef
函数中作为参数
// 定义
const forwardRender: React.ForwardRefRenderFunction<
HTMLDivElement,
AppProps
> = ({ value }, ref) => {
return <div ref={ref} />;
};
const App = React.forwardRef(forwardRender);
// 使用
const ref = useRef < HTMLDivElement > null;
return <App value="hello" ref={ref} />;
React.createContext
泛型有自动推断的功能,所以useContext
就不需要再写上类型了
interface ContextType {
getPrefixCls: (value: string) => string;
}
const context =
React.createContext <
ContextType >
{
getPrefixCls: (value) => `prefix-${value}`,
};
const App = () => {
const { getPrefixCls } = useContext(context);
getPrefixCls("App"); // prefix-App
return null;
};
React.cloneElement
如果使用的React.FC
定义的组件,它的children
类型默认是React.ReactNode
,需要显式转为React.ReactElement
const App: React.FC = ({ children }) => {
return React.cloneElement(children as React.ReactElement, { value: "hello" });
};
// 也可以覆写定义
const App: React.FC<{ children: React.ReactElement }> = ({ children }) => {
return React.cloneElement(children, { value: "hello" });
};
React.ComponentType
通过React.ComponentType<P>
定义的组件可以将变量名传入组件,在组件内调用,高阶组件通常会使用
interface AppProps {
value: string;
}
const App: React.FC<AppProps> = (props) => {
return null;
};
// React.ComponentType定义组件
function HOC<T>(Component: React.ComponentType<T>) {
return function (props: T) {
return <Component {...props} />;
};
}
const WrappedComponent = HOC(App);
// 调用
<WrappedComponent value="hello" />;