Typescript的应用与思考

合理的实践是什么样的

在大多数coding的场景下,我们习惯于自由开发。不同的代码风格造就着无数的人在coding的时候口吐芬芳。 对于上面的情况,我分享了一些最近使用reactnative和typescript进行配合开发,在搭建基础设施的时候,所产生的思考。

前言

本文不对reactnative进行过多讲解,主要以typescript为核心给我们所带来的思考:

大多数人对typescript的理解与印象,可能是说它是一个带类型的javascript,然后就没下文了。一直在那些类型给我们带来的语法糖的区域里。个人理解tyepescript的出现给我们前端带来了那些优秀的编程思想。如面向对象,ioc容器依赖注入,aop面向切面编程。基与这些我们可以搭建出一个代码结构比较健全的项目。虽说es6的出现,这些编程理念也可灵活的运用。但没法给我们带来静态类型的好处。

一、逻辑与UI分离

逻辑是什么?逻辑是一个纯类,包含属性,方法,可以继承其他类。我们所有的逻辑都应该封装到类里,不同的逻辑,分类不同类。相同逻辑可以使用依赖注入的方法,进行共享。不需要任何的展示方法(函数)

UI是什么?UI是一个函数,以react为例,hook函数来展示UI视图,这个函数只能包括,ui展示和事件绑定这些操作。复杂的逻辑尽量写到一个类里,在hook函数里导入并赋值到一个变量里进行api处理。

每次去导入的类的时候还需要new 成一个对象来进行导入。yes?

no。当然不是,这样太过麻烦,并且导入一个类的时候,还要想办法进行组件间共享数据。相同的操作我们应该封装起来。以HOC的方式对组件进行封装。

下面我会进行详细讲解。

二、reactnative是什么?

reactnatie可以使用react来开发移动原生应用,其通过react 的虚拟dom 借助于javascript core 引擎 给原生发事件通知,原生端订阅到组件的大小,位置等信息给原生组件(android ui,ios ui),最后由原生组件来渲染,从而来提高app的性能问题。当然这种渲染方式也是有弊端的,reactnaive也有相应的解决方案。

三、面向对象的编程理念

1、面向对象的三大特征

封装   继承   多态 (相信大家对于他们了解并不少,不在这里解释了)

类里面有一个很重要的概念,没错它就是构造函数constructor,进行一些初始化操作,下文 会用到。可用于依赖注入共享一些数据

import CommonStore from '../../stores/CommonStore';//导入通用类
import {injectable, autoInjectable, injectAll} from 'tsyringe';
@injectable()
class User{  name:string='德玛西亚'; //属性 constructor( public commonStore: CommonStore //构造器依赖注入 ) { super(this)}} 

上面的代码没太理解没关系,接下会讲解到。

四、ioc容器依赖注入

1、ioc是什么

IOC又叫依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中 就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

看上图,对象A和对象B,对象之间已经没有了耦合关系,彼此毫无联系,但又通过IOC把系统中的所有对象粘合在一起发挥作用。

所以对象A里可以共享对象B的数据,看起来和对象继承很像,那多继承呢,没法在一个对象里共享多个对象,IOC容器可以

2、组件之间共享对象

上文讲到,对象间可进行依赖注入共享数据。那么问题来了,如何在hook函数组间里共享这些数据呢?有人说,直接导入对象。对,那如何导入呢。前文说过我们所有的逻辑都是类,那么导入一次,就new 一次。可以是可以,不够优雅。来,优雅一点怎么搞呢。有人还记得context对象,组件间共享数据的一种。content对象提供了一个组件provider,改组件通过value属性来注入所要共享的对象,组件provider包裹这子组件。也就是是每一个被组件provider所包裹的子组件就可以拿到注入进来的对象。ok,逻辑理清了。看如何操作。

3、使用tsyringe实现IOC

[tsyringe -> 用于TypeScript/JavaScript的轻量级依赖注入容器,用于构造函数注入。

1.封装context对象 (react提供了createContext方法来创建一个context对象)

2.本地注入store(注入共享对象)

4、封装context对象

 /**
 * @Description:封装context对象
 * @date 2022/8/31
*/
import React, { useContext } from 'react'
import invariant from 'invariant'
import type { DependencyContainer } from 'tsyringe'
 
export const LocalStoreContext = React.createContext<any>(null)
LocalStoreContext.displayName = 'LocalStoreContext'
 
export function useLocalStore<T>(): T {const store: T = useContext(LocalStoreContext)invariant(store, 'local store is not exist!')return store
}
 
export const StoreContainerContext = React.createContext<DependencyContainer | null>(null)
StoreContainerContext.displayName = 'StoreContainerContext' 

上面用react提供了createContext方法创建一个了普通的context对象,着重说下DependencyContainer,你可看成我们注入依赖时所需要令牌,通过createContext创建了这个实例。

5、本地注入store(注入共享对象)

/**
 * @Description:本地注入store
 * @date 2022/8/31
*/
import React, { useContext, useMemo } from 'react'
import { container, Lifecycle,InjectionToken, } from 'tsyringe'
import hoistNonReactStatic from 'hoist-non-react-statics'
import { LocalStoreContext, StoreContainerContext } from '../../until/ContextHelpers';
 
export function withLocalStore<T extends JSX.IntrinsicAttributes, S>(WrappedComponent: React.ComponentType<T>,storeClass: { new (...args: any[]): S }
): React.ComponentType<T> {function WithLocalStoreHoc(props: T) {const superContainer = useContext(StoreContainerContext) || containerconst selfContainer = useMemo(() => {const componentContainer = superContainer.createChildContainer()if (!componentContainer.isRegistered(storeClass, false)) {componentContainer.register(storeClass,{ useClass: storeClass },{ lifecycle: Lifecycle.Singleton })}return componentContainer}, [superContainer])
 return (<StoreContainerContext.Provider value={selfContainer}><LocalStoreContext.Provider value={selfContainer.resolve(storeClass)}><WrappedComponent {...props} /></LocalStoreContext.Provider></StoreContainerContext.Provider>)}
 WithLocalStoreHoc.displayName = `WithLocalStoreHoc(${getDisplayName(WrappedComponent)})`hoistNonReactStatic(WithLocalStoreHoc, WrappedComponent)return WithLocalStoreHoc
}
 
function getDisplayName<T>(WrappedComponent: React.ComponentType<T>) {return WrappedComponent.displayName || WrappedComponent.name || 'Component'
} 

当我们使用tsyringe进行依赖注入时

1.创建一个DelayedConstructor的实例,其实就是token验证

2.注册一个共享数据(对象),这里还牵扯到单例模式,该对象只能创建为单例模式,只会有一个实例共享对象。new 的时候就数据就不会被重置。

3.DelayedConstructor对象提供了provider组件,通过value属性注入这个对象,解析着这个共享数据

4.DelayedConstructor对象提供了provider包裹着子组件,子组件间共享数据对象

5.在通过useContext hook 使用provider组件底层组件间的共享

五、使用IOC和Mobx进行合理的逻辑与UI分离

1、逻辑处理

import {observable, runInAction, makeObservable, action} from 'mobx'
import {injectable, autoInjectable, injectAll} from 'tsyringe';
import UserStore from "../../stores/UserStore";
import CommonStore from '../../stores/CommonStore';
import {UserInfo} from '../../stores/model/Uesr';
 
@injectable()
export default class HomeStore {
 @observable userInfo: UserInfo | undefined;
 constructor( public userStore: UserStore,public commonStore: CommonStore ) {makeObservable(this)}
 
 @action.boundgetUserInfo() {this.userStore?.getInfo();this.userInfo = this.userStore?.userInfo;}
 
 
} 

1.使用mobx中@observable进行数据响应时处理

2.使用tsyringe的@injectable()进行依赖注解在constructor函数初始化参数的时候,传了一个类

2.UI处理

/**
 * @Description:主页
 * @date 2022/8/29
 */
import {View, Text, StyleSheet, ScrollView, Animated} from 'react-native';
import React, {useContext, useRef} from 'react';
import {observer} from 'mobx-react';
import HomeStore from './homeStore';
import {withLocalStore} from '../../components/withLocalStore';
import {useLocalStore} from '../../until/ContextHelpers';
import {useMount} from 'ahooks';
import {LargeList} from "react-native-largelist";
import {ChineseWithLastDateHeader} from "react-native-spring-scrollview/Customize";
 
interface IProps {}
 
const HomeScreen = (props: IProps) => {
 const store = useLocalStore<HomeStore>();useMount(() => {store.getUserInfo();console.log('userInfo', store.userInfo?.userName)})
 
 return <View style={styles.body}> </View>
}
 
export default withLocalStore(observer(HomeScreen), HomeStore); 

1.通过封装的高阶组件withLocalStore进行组件包裹。observer是mobx提供的,可使该组件响应时监听数据的变化,视图更改。

2.通过封装useLocalStore传入一个类(依赖),得到一个可共享的对象。该对象封装所有的逻辑api处理。

总结

以上就是今天要讲的内容,本文介绍了ioc的使用及一些概念上的东西,而typescript提供了大量能使我们快速便捷开发的编程思想。对于上文有不同见解的,可以开放的进行相互学习。欢迎留言自己的不同理解。

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值