react ts环境搭建及ts格式写法

1、脚手架启动
	npx create-react-app 项目名称  --template typescript  

	官方建议:
	If you've **previously installed create-react-app globally** 
	via npm install -g create-react-app, we recommend you uninstall
	 the package using **npm uninstall -g create-react-app** to ensure that npx always uses the latest version.
    **Global installs of create-react-app are no longer supported.**
	
	不使用脚手架手动创建:
		react和react-dom都需要按照@types对应的声明文件,解析tsx语法使用ts-loader/awesome-typescript-loader/babel

2、创建.tsx文件

3、类型约束(类组件不写接口放到继承组件的泛型里会报错)
	(1)类组件
	 	接收参数的组件需要接口声明并使用泛型
	 	
		class App extends Component{ 泛型P:参数props,泛型S:状态state,泛型SS:snapshot
			
			状态:
				state:S={
					...
				}
				readonly state:Readonly= {	该方法可避免this.state.x去改变状态,使用了Readonly映射类型,只对一级属性有用
					...
		    	}
				构造函数中设置状态:
				  constructor(props:P) {
				    super(props);
				    this.state = {
				      ...
				    }
				  }
			
		}
		
	(2)函数组件
		function(props:any或者定义接口约束)
		{...}
		或
		
		import React from 'react'
		import React,{FC,SFC} from 'react'
			
		interface P {
			count: number
		}
		
		const xx:React.FC

= props => { 其中: (1)React.SFC表示无状态函数,泛型P约束props (2)使用React提供的FC进行约束,会隐式在约束中提供一个children属性,可以之间props.children实现插槽 (3)使用xx.defaultProps为指定参数赋默认值是,FC约束的函数的接口中的指定属性必须是可选的,普通函数不用 import React from 'react' interface helo{ name: string, age?:number } const Hello: React.FC = (props) => { return (

哈哈哈+{props.name}

) } Hello.defaultProps = { age:12 } export default Hello; } const xx:FC = props => { ... } (3)高阶函数(通过一个组件返回另一个组件) 1、使用React.ComponentType

约束传入的组件 泛型P约束props React.ComponentType:React.ComponentClass | React.FunctionComponent

的联合类型 2、进行约束 因为传入的组件本身就是一个具有类型约束的组件,所以可以直接使用其泛型(在调用时自动推断参数类型)来进行高阶函数的约束 interface L{ loading:boolean } 泛型P使得传入高阶函数的参数约束和传入组件的参数一致 function Hello

(WrapComp:React.ComponentType

) { 组件类型:泛型P约束props,是React.ComponentClass | React.FunctionComponent

的联合类型 return class extends Component

{ 通过交叉接口添加高阶函数本身的参数约束 render() { const { loading, ...props } = this.props; return ( loading ?

loading
: 因为不知道剩余参数的类型,使用断言排除报错 ) } } } export default Hello(Wrap); 使用该高阶组件的时候,传入的参数必须满足组件的泛型P代表的约束和交叉接口扩展的约束 (4)Hooks const [test, setTest] = useState(null); useCallback<()=>void>(()=>{},[]) (4.5)event事件类型约束: clickHandle = (e:React.事件类型) => { React.FormEvent 表单事件,无法获取到value属性 泛型精确化: React.FormEvent html的input事件,可以获取到value属性 React.MouseEvent 鼠标事件 React.KeyboardEvent 键盘事件 React.TouchEvent 手势事件 } (5)路由: cnpm install react-router-dom --save cnpm install @types/react-router-dom 其他写法一样 (6)Redxu: 1、安装 cnpm install -S redux react-redux @types/react-redux 不需要安装@types/redux,因为Redux已经自带了声明文件(.d.ts文件)。 2、创建types文件夹,其中的index.tsx文件放置reducer中state的接口格式 export interface IStoreState{ x:类型 } 3、创建action-type.tsx文件,放置action的type常量 (1)每个常量包括常量本身及其类型格式,方便在定义action接口时,定义type的类型 (2)当类型格式type名称和常量名称相同时,在导出时,会自动识别接口中的type和常量 export const INCREMENT='INCREMENT' export type INCREMENT=typeof INCREMENT 4、创建action.tsx文件 (1)每个action包括及接口格式和自身函数表达式 (2)还要导出使用联合类型声明的接口格式总和 1、方便在组件mapDispatchToPros中,约束dispatch参数格式, 2、方便约束reducer中action的参数格式 (3)引入定义的常量 (4)当常量文件中类型格式type名称和常量名称相同时,在导出时,会自动识别接口中的type和常量 import * as constants from '../constants/index' export interface IIncrement{ type:constants.INCREMENT } export interface IDecrement{ type:constants.DECREMENT } export type EnthusiamAction=IIncrement | IDecrement; export function increment():EnthusiamAction{ return { type:constants.INCREMENT } } export function decrement():EnthusiamAction{ return { type:constants.DECREMENT } } 5、定义reducer.tsx (1)引入types文件夹中定义的state接口约束,约束state (2)引入action文件中的对象联合约束类型,约束action (3)引入action-type中定义的常量,做switch的case import {EnthusiamAction} from '../actions' import { IStoreState } from '../types/index'; import {INCREMENT,DECREMENT} from '../constants/index' export function count(state:IStoreState={count:0},action:EnthusiamAction) { switch(action.type) { case INCREMENT: return { count:state.count+1 } default: return state } } 6、创建store.js文件,导出store (1)redux-devtools-extension的使用和之前一样 (2)导出store的方式和之前一样 7、在index.tsx中使用Provider包裹 使用方式和之前一样 8、在组件中使用 (1)从'react-redux'中引入connect (2)引入types文件夹中的对state的约束接口,约束mapStateToProps的state参数 (3)引入action.tsx文件中的接口联合类型约束,约束mapDispatchToProps的dispatch函数 mapDispatchToProps(dispatch:Dispatch) Dispatch为type声明的函数格式,泛型约束参数 源码:type Dispatch = (value: A) => void; (4)组件分别创建props接口和state接口,约束传入的状态和参数,放在继承类的泛型上进行约束 (5)注意在设置action的函数约束时,返回类型要设置成void,不能设置成返回对象 import React,{Component, Dispatch} from 'react' import * as actions from '../actions/index' import {IStoreState} from '../types' import {connect} from 'react-redux' interface IProps{ title:string, myclick:(data:string)=>void, count:number, increment:()=>void; decrement:()=>void; } interface IState{ count:number } class App extends Component{ ... } function mapStateToProps(state:IStoreState){ return{ count:state.count } } function mapDispatchToProps(dispatch:Dispatch){ //Dispatch是个函数类型,泛型约定了参数 return{ increment:()=>dispatch(actions.increment()), decrement:()=>dispatch(actions.decrement()) } } export default connect(mapStateToProps,mapDispatchToProps)(App) 4、文件拷贝 ts文件可通过tsconfig指定输出,但其他类型文件不能 方式一:通过shelljs库,将文件拷贝 shelljs.cp("R"," public' , "dist") 通过递归拷贝,将public文件夹拷贝的dist目录下

代码示例:
types下的index.tsx:


export interface IStoreState{
     
    count:number
}

constants下的index.tsx:

export const INCREMENT='INCREMENT'
export type INCREMENT=typeof INCREMENT


export const DECREMENT='DECREMENT'
export type DECREMENT=typeof DECREMENT

action下的index.tsx:

import * as constants from '../constants/index'


export interface IIncrement{
     
    type:constants.INCREMENT
}

export interface IDecrement{
     
    type:constants.DECREMENT
}

export type EnthusiamAction=IIncrement | IDecrement;


export function increment():EnthusiamAction{
     

    return {
     
        type:constants.INCREMENT
    }
}

export function decrement():EnthusiamAction{
     
    return {
     
        type:constants.DECREMENT
    }
}

reducers下的index.tsx:

import {
     EnthusiamAction} from '../actions'
import {
      IStoreState } from '../types/index';
import {
     INCREMENT,DECREMENT} from '../constants/index'

export  function count(state:IStoreState={
     count:0},action:EnthusiamAction)
{
     
    switch(action.type)
    {
     
        case INCREMENT:
            return {
     
                count:state.count+1
            }
        
        case DECREMENT:
            return{
     
                count:state.count-1
            }
        
        default:
            return state
    }
}

store下的index.tsx:

import {
     createStore} from 'redux'
import {
     count} from '../reducers/index'
import {
     composeWithDevTools} from 'redux-devtools-extension'

const store = createStore(count,composeWithDevTools());

export default store;

index.tsx:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import AppRouter from './router/appRouter'
import {
     Provider} from 'react-redux'
import store from './store/index'

ReactDOM.render(
  <Provider store={
     store}>
    <React.Fragment>
      <AppRouter />
    </React.Fragment>
  </Provider>
  ,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

路由文件:

import React,{
     Component} from 'react'
import {
     HashRouter,Switch,Route} from 'react-router-dom'
import App from '../App'

class App2 extends Component{
     

    render()
    {
     
        return(

            <div>
                <HashRouter>
                    <Switch>
                       <Route exact path='/' component={
     App}>
                        
                       </Route> 

                    </Switch>   

                </HashRouter>
            </div>
        )
    }
}

export default App2

App.tsx:

import React from 'react';
import logo from './logo.svg';
import './App.css';
import Hello from './components/hello'
import List from './pages/list'



function App() {
     

  function myclick(data:string)
  {
     
    console.log('父组件')
    console.log(data);
  }

  return (
    <div className="App">
        ts
        <Hello title='标题' myclick={
     myclick}></Hello>
        <List></List>
    </div>
  );
}

export default App;

子组件Hello:

import React,{
     Component, Dispatch} from 'react'
import {
      Button } from 'antd';
import * as actions from '../actions/index'
import {
     IStoreState} from '../types'
import {
     connect} from 'react-redux'


interface IProps{
     
    title:string,
    myclick:(data:string)=>void,
    count:number,
    increment:()=>void;
    decrement:()=>void;
}

interface IState{
     
    count:number
}

class App extends Component<IProps,IState>{
     

    constructor(props:IProps){
     
        super(props);
        this.state={
     
            count:2
        }

    }

    // readonly state:Readonly= {
     
	// 	count: 1
    // }
    componentDidMount()
    {
     
        // this.state.count=3;
        // this.setState({
     
        //     count:5
        // });
    }

    click()
    {
     
        this.setState({
     
            count:7
        });
    }
    send()
    {
     
        console.log('111');
        this.props.myclick('ahh');
    }
    increment()
    {
     
        this.props.increment()
    }
    decrement()
    {
     
        this.props.decrement()
    }

    render()
    {
     
        return(

            <div>
                hello
                {
     this.props.title}
                {
     this.state.count}
                redux:{
     this.props.count}
                <Button onClick={
     this.click.bind(this)}>点击</Button>
                <Button onClick={
     this.send.bind(this)}>send</Button>

                <Button onClick={
     this.increment.bind(this)}>增加</Button>
                <Button onClick={
     this.decrement.bind(this)}>减少</Button>
            </div>
        )
    }
}

function mapStateToProps(state:IStoreState){
     
    return{
     
        count:state.count
    }
}

function mapDispatchToProps(dispatch:Dispatch<actions.EnthusiamAction>){
      //Dispatch是个函数类型,泛型约定了参数
    return{
     
        increment:()=>{
     dispatch(actions.increment());},
        decrement:()=>dispatch(actions.decrement())
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(App)

// import React,{useState} from 'react'


// interface IProps{
     
//     title:string
//   }

// function App(props:IProps){
     

//   return(

//     
// {props.title} //
// ) // } // export default App

子组件List:

import React,{
     Component} from 'react'
import ListView from '../components/listView'

interface IState {
     
    dataInfo:{
     
        info:number[]
    }
}
class App extends Component<{
     },IState>{
     

    constructor(props:any){
     
        super(props);
        this.state={
     
            dataInfo:{
     
                info:[]
            }
        }
    }

    componentDidMount()
    {
     
        this.setState({
     
            dataInfo:{
     
                info:[1,2,3]
            }
        })
    }

    render()
    {
     
        return(

            <div>
               {
     
                   this.state.dataInfo.info.length>0?
                   <div>
                       <ul>
                           {
     
                               this.state.dataInfo.info.map((item,index)=>{
     
                                   return <ListView key={
     index} content={
     item}></ListView>
                               })
                           }
                       </ul>


                   </div>: <div>数据加载中</div>
               }
            </div>
        )
    }
}

export default App

List子组件ListView:

import React,{
     Component} from 'react'

interface IProps{
     
    content:number
}

class App extends Component<IProps,any>{
     

    render()
    {
     
        return(

            <div>
                {
     this.props.content}
            </div>
        )
    }
}

export default App

高阶组件:

import React, {
      Component } from 'react';
import Wrap from './wrapComp'

interface L{
     
  loading:boolean
}


function Hello<P>(WrapComp:React.ComponentType<P>) {
       //组件类型:泛型P约束props,是React.ComponentClass | React.FunctionComponent

的联合类型 return class extends Component<P & L>{ render() { const { loading, ...props } = this.props; return ( loading ? <div>loading</div> : <WrapComp { ...props as P}/> ) } } } export default Hello(Wrap);

高阶组件传入的组件

import React from 'react';

interface helos{
     
  name?: string,
  age?: number,
  add:string
}

const Hello: React.FC<helos> = (props) => {
     
  return (<h1>哈哈哈+wrap</h1>)
}


export default Hello;

高阶组件调用:

      <HelloHigh add={
     'ww'} loading={
     false} ></HelloHigh>

你可能感兴趣的:(react)