您现在的位置是:网站首页> 编程资料编程资料
在React项目中使用TypeScript详情_React_
2023-05-24
225人已围观
简介 在React项目中使用TypeScript详情_React_
前言:
本文主要记录我如何在React项目中优雅的使用TypeScript,来提高开发效率及项目的健壮性。
项目目录及ts文件划分
由于我在实际项目中大部分是使用umi来进行开发项目,所以使用umi生成的目录来做案例。
. ├── README.md ├── global.d.ts ├── mock ├── package.json ├── src │ ├── assets │ ├── components │ │ └── PublicComA │ │ ├── index.d.ts │ │ ├── index.less │ │ └── index.tsx │ ├── layouts │ ├── models │ ├── pages │ │ ├── PageA │ │ │ ├── index.d.ts │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── index.less │ │ └── index.tsx │ └── utils ├── tsconfig.json ├── typings.d.ts └── yarn.lock
在项目根目录下有typings.d.ts和global.d.ts这两个文件, 前者我们可以放置一些全局的导出模块,比如css,less, 图片的导出声明;后者可以放一些全局声明的变量, 接口等, 比如说window下全局变量的声明等。
如下:
// typings.d.ts declare module '*.css'; declare module '*.less'; declare module "*.png"; declare module "*.jpeg"; declare module '*.svg' { export function ReactComponent(props: React.SVGProps): React.ReactElement const url: string export default url } // global.d.ts interface Window { helloWorld: () => void; }接下来介绍一下src目录:
- assets 存放静态资源如图片/视频/音频等, 参与webpack的打包过程
- layouts 存放公共布局
- components 存放全局公共组件
- models dva的models文件夹
- pages 存放页面的目录, 内部可以有页面组件components, 结构类似于全局的components
- utils 存放js工具库, 请求库等公共js文件
在pages和components中有存放当前组件/页面所需要的类型和接口声明的index.d.ts。另外如models中的文件由于是每个model私有类型和接口声明,所以可以直接在文件内部去声明。 具体的目录规划如上,可以根据实际项目来做更合理的划分。
在项目中使用TypeScript具体实践
组件声明
- 函数组件 推荐使用
React.FC来表示函数类型,当使用该类型定义组件时,props中会默认带有children属性。
interface IProps { count: number } const App: React.FC = (props) => { const {count} = props; return ( count: {count} ); } - 类组件 类组件接受两个参数,第一个是props的定义,第二个是state的定义,如果使用
React.PureComponent定义组件,则还有第三个参数,表示getSnapshotBeforeUpdate的返回值。
interface IProps { name: string; } interface IState { count: number; } class App extends React.Component { state = { count: 0 }; render() { return ( {this.state.count} {this.props.name} ); } } React Hooks使用
useState
声明定义:
function useState(initialState: S | (() => S)): [S, Dispatch>]; // convenience overload when first argument is omitted /** * Returns a stateful value, and a function to update it. * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#usestate */ function useState (): [S | undefined, Dispatch>]; /** * An alternative to `useState`. * * `useReducer` is usually preferable to `useState` when you have complex state logic that involves * multiple sub-values. It also lets you optimize performance for components that trigger deep * updates because you can pass `dispatch` down instead of callbacks. * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#usereducer */
如果初始值能够体现出类型,那么可以不用手动声明类型,TS会自动推断出类型。如果初始值为null或者undefined则需要通过泛型显示声明类型。
如下:
const [count, setCount] = useState(1); const [user, setUser] = useState(null);
useRef
声明定义:
function useRef(initialValue: T): MutableRefObject ; // convenience overload for refs given as a ref prop as they typically start with a null value /** * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument * (`initialValue`). The returned object will persist for the full lifetime of the component. * * Note that `useRef()` is useful for more than the `ref` attribute. It's handy for keeping any mutable * value around similar to how you'd use instance fields in classes. * * Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type * of the generic argument. * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#useref */
使用该Hook时,要根据使用场景来判断传入泛型类型,如果是获取DOM节点,则传入对应DOM类型即可;如果需要的是一个可变对象,则需要在泛型参数中包含'| null'。
如下:
// 不可变DOM节点,只读 const inputRef = useRef(null); // 可变,可重新复制 const idRef = useRef (null); idRef.current = "abc";
useCallback
声明定义:
function useCallbackany>(callback: T, deps: DependencyList): T; /** * `useMemo` will only recompute the memoized value when one of the `deps` has changed. * * Usage note: if calling `useMemo` with a referentially stable function, also give it as the input in * the second argument. * * ```ts * function expensive () { ... } * * function Component () { * const expensiveResult = useMemo(expensive, [expensive]) * return ... * } * ``` * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#usememo */
useCallback会根据返回值自动推断出类型,如果传入的参数不指定类型,则会默认为any,所以为了严谨和可维护性,一定要指定入参的类型。也可以手动传入泛型指定函数类型。
如下:
// 会自动推导出类型: (a: number, b: number) => number; const add = useCallback((a: number, b: number) => a + b, [a, b]) // 传入泛型,则指定函数类型 const toggle = useCallback<(a: number) => number>((a: number) => a * 2, [a])
useMemo
声明定义:
function useMemo(factory: () => T, deps: DependencyList | undefined): T; /** * `useDebugValue` can be used to display a label for custom hooks in React DevTools. * * NOTE: We don't recommend adding debug values to every custom hook. * It's most valuable for custom hooks that are part of shared libraries. * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#usedebugvalue */
useMemo和useCallback类似,只是定义类型为具体返回值的类型,而不是函数的类型。
如下:
// 会自动推导出类型: number; const add = useCallback((a: number, b: number) => a + b, [a, b]) // 传入泛型,则指定函数类型 const toggle = useCallback((a: number) => a * 2, [a])
useContext
声明定义:
function useContext(context: Context /*, (not public API) observedBits?: number|boolean */): T; /** * Returns a stateful value, and a function to update it. * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#usestate */
useContext会根据传入的上下文对象自动推导出context的类型,当然也可以使用泛型来设置context的类型,
如下:
interface ITheme { color: string; } const ThemeContext = React.createContext({ color: "red" }); // 自动推导出类型为ITheme const theme = useContext(ThemeContext); // 等同于const theme = useContext(ThemeContext); useReducer
声明定义:
function useReducer>( reducer: R, initialState: ReducerState , initializer?: undefined ): [ReducerState , Dispatch >]; /** * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument * (`initialValue`). The returned object will persist for the full lifetime of the component. * * Note that `useRef()` is useful for more than the `ref` attribute. It's handy for keeping any mutable * value around similar to how you'd use instance fields in classes. * * @version 16.8.0 * @see https://reactjs.org/docs/hooks-reference.html#useref */
上面只列出了一种类型定义,我在项目中也是使用这种定义去指定useReducer的类型。普通的案例如下:
type StateType = { name: string; age: number; } type Actions = { type: 'Change_Name'; payload: string; } | { type: 'Change_Age'; payload: number; } const initialState = { name: '小明', age: 18 } const reducerAction: Reducer = ( state, action, ) => { switch (action.type) { case 'Change_Name': return { ...state, name: action.payload }; case 'Change_Age': return { ...state, age: action.payload }; default: return state; } }; function Index() { const [state, dispatch] = useReducer(reducerAction, initialState); return ( 姓名:{state.name}年龄:{state.age} ); } 可以看到,这样能够得到正确的类型推断,但是略微繁琐。
<
相关内容
- uniapp路由uni-simple-router实例详解_javascript技巧_
- 关于Vue-cli3烦人的eslint问题_vue.js_
- Vue 中的 computed 和 watch 的区别详解_vue.js_
- 解决VuePress页面乱码问题_vue.js_
- JavaScript中执行上下文和执行栈_javascript技巧_
- vue中的公共方法调用方式_vue.js_
- Vue3初探之ref、reactive以及改变数组的值_vue.js_
- vue-devtools 打开源码位置实现过程_vue.js_
- js 实现Material UI点击涟漪效果示例_JavaScript_
- js 实现验证码输入框示例详解_JavaScript_
