前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >入门 TypeScript 编写 React

入门 TypeScript 编写 React

作者头像
icepy
发布于 2019-06-24 09:55:14
发布于 2019-06-24 09:55:14
5.3K00
代码可运行
举报
文章被收录于专栏:子曰五溪子曰五溪
运行总次数:0
代码可运行

使用 create-react-app 开启 TypeScript

Create React App 是一个官方支持的创建 React 单页应用程序的CLI,它提供了一个零配置的现代构建设置。当你使用 Create React App 来创建一个新的 TypeScript React 工程时,你可以运行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ npx create-react-app my-app --typescript
$ # 或者
$ yarn create react-app my-app --typescript

如果在已有的工程中添加,也非常简单:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ npm install --save typescript @types/node @types/react @types/react-dom @types/jest
$ # 或者
$ yarn add typescript @types/node @types/react @types/react-dom @types/jest

从零配置

创建 index.html 文件,以及src 目录,在 src目录中创建 index.tsx

TypeScript 的文件格式是 tsx

接下来安装必要的包和配置 package.json 文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"scripts": {
  "dev": "MODE=development webpack -w --mode=development",
  "build": "MODE=production webpack --mode=production"
},
"dependencies": {
  "@types/react": "^16.8.13",
  "@types/react-dom": "^16.8.3",
  "react": "^16.8.6",
  "react-dom": "^16.8.6"
},
"devDependencies": {
  "awesome-typescript-loader": "^5.2.1",
  "source-map-loader": "^0.2.4",
  "typescript": "^3.4.3",
  "webpack": "^4.29.6",
  "webpack-cli": "^3.3.0"
}

创建 tsconfig.jsonwebpack.config.js 文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "lib": ["dom","es2015"],
    "jsx": "react",
    "sourceMap": true,
    "strict": true,
    "noImplicitAny": true,
    "baseUrl": "src",
    "paths": {
      "@/*": ["./*"],
    },
    "esModuleInterop": true,
    "experimentalDecorators": true,
  },
  "include": [
    "./src/**/*"
  ]
}
  • jsx 选择 react
  • lib 开启 domes2015
  • include 选择我们创建的 src 目录
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var fs = require('fs')
var path = require('path')
var webpack = require('webpack')
const { CheckerPlugin } = require('awesome-typescript-loader');
var ROOT = path.resolve(__dirname);

var entry = './src/index.tsx';
const MODE = process.env.MODE;
const plugins = [];
const config = {
  entry: entry,
  output: {
    path: ROOT + '/dist',
    filename: '[name].bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.ts[x]?$/,
        loader: [
          'awesome-typescript-loader'
        ]
      },
      {
        enforce: 'pre',
        test: /\.ts[x]$/,
        loader: 'source-map-loader'
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.json'],
    alias: {
      '@': ROOT + '/src'
    }
  },
}

if (MODE === 'production') {
  config.plugins = [
    new CheckerPlugin(),
    ...plugins
  ];
}

if (MODE === 'development') {
  config.devtool = 'inline-source-map';
  config.plugins = [
    new CheckerPlugin(),
    ...plugins
  ];
}

module.exports = config;

类组件的使用

类组件是目前来说使用的最频繁的一种,因此我们需要了解到它。

Props 和 State

首先创建 Props 和 State 接口,Props 接口接收一个 name 参数,State 接口接收 color:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IProps {
  name: string;
}

interface IState {
  color: "red" | "blueviolet"
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Home extends React.Component<IProps, IState> {
  constructor(props: IProps){
    super(props);
    this.state = {
      color: "red"
    }
  }

  public onClickColor = () => {
    const { color } = this.state;
    if (color === "red") {
      this.setState({
        color: "blueviolet"
      });
    }
    if (color === "blueviolet") {
      this.setState({
        color: "red"
      });
    }
  }

  public render(){
    const { name } = this.props;
    const { color } = this.state;
    return (
      <div>
        <span style={{ color }}>{ name }</span>
        <button onClick={this.onClickColor}>变颜色</button>
      </div>
    );
  }
}


export default Home;

如图:

App 中使用 Home 组件时我们可以得到明确的传递参数类型。

处理 Event 对象

有时候我们需要处理一下 Event 对象,一般 change 事件我们可以使用 React.ChangeEvent,click 事件可以使用 React.MouseEvent ,它们都接收一个 Element,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
onClickColor = (ev: React.MouseEvent<HTMLButtonElement>) => {
  //
}

PureComponent

我们都知道 React 的刷新机制,因此如果每一次的变动都要刷新一下界面,这对于应用程序的性能来说是一个非常不科学的事情,因此在没有 PureComponent 之前,我们都需要手动使用 shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean; 来确认到底要不要刷新界面,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import * as React from "react";
import Typography from "@material-ui/core/Typography";

interface IMyComparisonProps {
  text: string;
}

class MyComparison extends React.Component<IMyComparisonProps> {
  constructor(props: IMyComparisonProps) {
    super(props);
  }

  public shouldComponentUpdate(nextProps: IMyComparisonProps) {
    if (this.props.text === nextProps.text) {
      return false;
    }
    return true;
  }

  public render() {
    const { text } = this.props;
    return (
      <Typography>
        Component 值:{ text }
      </Typography>
    );
  }
}

export default MyComparison;

如果返回的是 false 那么将不调用 render,如果是 true 则调用 render

但是如果我们使用 PureComponent 那么就省略了这一步,我们可以不用关心组件是否要刷新,而是 React.PureComponent 来帮我们决定。在使用之前,我们还有一些注意事项要了解,React.PureComponent 是一个和 React.Component 几乎相同,唯一不同的是 React.PureComponent 帮助我们完成了 shouldComponentUpdate 的一些交浅的比较,因此在我们真实的组件设计中,我们一般会用于最后一个关键点的组件上。

Portals

ReactDOM 中提供了一个方法 createPortal,可以将节点渲染在父组件之外,但是你可以依然使用父组件上下文中的属性。这个特性在我所讲的全局对话框或者提示框中非常有用,它脱离了父节点的容器,插在最外层,在样式上就能通过 position: fixed 来覆盖整个文档树。

我们在 state 中定义了一个 open,它只接收一个布尔值,用于打开提示框或关闭提示框架,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export interface IPortalsProps {}

export interface IPortalsState {
  open: boolean;
}

然后我们定义两个方法用于设置 open

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public clickHandler = () => {
  this.setState({
    open: true,
  });
}

public clickHandlerClose = () => {
  this.setState({
    open: false,
  });
}

最后在 render 方法中使用 ReactDOM.createPortal 来创建一个全局的 Alert,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import * as React from "react";
import * as ReactDOM from "react-dom";
import Button from "@material-ui/core/Button";
import Alert from "../Alert";
import {
  IPortalsProps,
  IPortalsState,
} from "./types";

class MyPortals extends React.Component<IPortalsProps, IPortalsState> {

  constructor(props: IPortalsProps) {
    super(props);
    this.state = {
      open: false,
    };
  }

  public clickHandler = () => {
    this.setState({
      open: true,
    });
  }

  public clickHandlerClose = () => {
    this.setState({
      open: false,
    });
  }

  public render() {
    const { open } = this.state;
    return (
      <div>
        <Button
          variant="outlined"
          color="primary"
          onClick={this.clickHandler}
        >
          提示
        </Button>
        {
          ReactDOM.createPortal(
            <Alert
              open={open}
              message="React Component Portals Use"
              handleClose={this.clickHandlerClose}
            />,
            document.getElementById("app")!,
          )
        }
      </div>
    );
  }
}

export default MyPortals;

Fragments

Fragments 可以让我们减少生成过多有副作用的节点,以往 render 必须返回单一节点,因此很多组件常常会产生过多无用的 divReact 根据这样的情况给予了一个组件来解决这个问题,它就是 Fragment

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public render(){
  return (
    <React.Fragment>
      <div></div>
      <div></div>
    </React.Fragment>
  )
}

//or

public render(){
  return (
    <>
      <div></div>
      <div></div>
    </>
  )
}

函数组件以及 Hooks

Hooks 自去年10月发布以来,函数组件就派上了用场,React 的函数组件主要引用 SFC 返回(React.FunctionComponent),当然你也可以不引用 SFC 类型只不过返回的是(JSX.Element),这就是区别。

useState

以前:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IFuncComp {
  name: string;
}
const FuncComp: React.SFC<IFuncComp> = ({ name }) => {
  return (
    <div>{ name }</div>
  )
}

现在:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IFuncComp2 {
  name: string;
}

const FuncComp2: React.SFC<IFuncComp2> = ({ name }) => {
  const [ num, setNum ] = React.useState<number>(0);
  return (
    <div>
      { name } { num }
      <button onClick={() => {
        setNum(num + 1);
      }}>+</button>
    </div>
  )
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

由于 useState 被定义为一个泛型函数,因此类型可以由我们自己来指定。

useEffect

当你使用 useEffect 时,我们可以传入第三个参数来决定是否执行这个 callback ,这对于优化你的应用至关重要。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
React.useEffect(() => {

}, [num]);

useContext

对于 useContext 当你需要共享数据时可用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IContext {
  name: string;
}
const initContext: IContext = {
  name: "",
};
const context = React.createContext(initContext);

const FuncMainContext = () => {
  return (
    <>
      <context.Provider value={initContext}>
        <FuncContext />
      </context.Provider>
    </>
  )
}

const FuncContext = () => {
  const va = React.useContext(context);
  return (
    <div>{ va.name }</div>
  )
}

useReducer

如果你已经习惯 redux 不妨来看看 useReducer,假设我们需要通过按钮来更改文本颜色:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IState {
  color: "red" | "blueviolet"
}

interface IAction {
  type: string;
  payload: any;
}

const reducer = (prevState: IState, action: IAction) => {
  const { type, payload } = action;
  switch(type){
    case "COLOR_CHANGE" : {
      return { ...prevState, color: payload };
    }
    default: {
      return prevState;
    }
  }
}

const App = () => {
  const initialState: IState = {
    color: "red"
  }
  const [state, dispatch ] = React.useReducer(reducer, initialState);
  return (
    <div>
      <span style={{ color: state.color }}>icepy</span>
      <button onClick={() => {
        dispatch({
          type: "COLOR_CHANGE",
          payload: state.color === "red" ? "blueviolet" : "red"
        });
      }}>change</button>
    </div>
  );
}

useRef

当我们需要来引用原生DOM来处理某件事情时,useRef 可以辅助我们完成这项工作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App = () => {
  const inputEl = React.useRef<HTMLInputElement>(null);
  const onButtonClick = () => {
    if (inputEl && inputEl.current) {
      inputEl.current.focus();
    }
  }
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus</button>
    </>
  );
}

useMemo

接下来我们可以说一说 useMemo ,这只能当作一次性能优化的选择,通常情况下假设我们的 state 有两个属性,它的场景可能如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App = () => {
  const [ index, setIndex ] = React.useState<number>(0);
  const [ str, setStr ] = React.useState<string>("");
  const add = () => {
    return index * 100;
  }
  return (
    <>
      <div>{index}-{str}-{add()}</div>
      <div>
        <button onClick={() => {
          setIndex(index + 1);
        }}>+</button>
        <input type="text" onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {
          setStr(ev.target.value);
        }}/>
      </div>
    </>
  );
}

无论如何修改 indexstr 都会引发 add() 的执行,这对于性能来说是很难接受的,因为 add() 只依赖于 index ,因此我们可以使用 useMemo 来优化此项。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App = () => {
  const [ index, setIndex ] = React.useState<number>(0);
  const [ str, setStr ] = React.useState<string>("");
  const add = React.useMemo(() => {
    return index * 100;
  }, [index]);
  return (
    <>
      <div>{index}-{str}-{add}</div>
      <div>
        <button onClick={() => {
          setIndex(index + 1);
        }}>+</button>
        <input type="text" onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {
          setStr(ev.target.value);
        }}/>
      </div>
    </>
  );
}

useMemo 的类型依赖于 factory 的返回值,我们可以观察一下它的描述文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;

useCallback

那么 useCallback 的使用和 useMemo 比较类似,但它返回的是缓存函数。 通常情况下,我们可以使用 useCallback 来处理父组件更新但不想子组件更新的问题,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IAppChildProps {
  callback: () => number;
}
const AppChild = ({ callback }: IAppChildProps) => {
  const [ index, setIndex ] = React.useState(() => callback());
  React.useEffect(() => {
    setIndex(callback());
  }, [callback])
  return (
    <div> { index }</div>
  );
}

const App = () => {
  const [ index, setIndex ] = React.useState<number>(0);
  const [ str, setStr ] = React.useState<string>("");
  const callback = React.useCallback(() => {
    return index * 100;
  }, [index]);
  return (
    <>
      <h1>{ str }</h1>
      <AppChild callback={callback} />
      <div>
        <button onClick={() => {
          setIndex(index + 1);
        }}>+</button>
        <input type="text" onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {
          setStr(ev.target.value);
        }}/>
      </div>
    </>
  );
}

useImperativeHandle

useImperativeHandle 可以让你使用 ref 将自定义的函数暴露给父组件,这种场景一般情况可以用于在父组件中操作子组件的DOM元素,需要和 forwardRef 配合使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IFancyInput {
  name: string;
}

interface IFancyInputRef {
  focus: () => void;
}

const fancyInput = (props: IFancyInput, ref: React.Ref<IFancyInputRef>) => {
  const inputEl = React.useRef<HTMLInputElement>(null);
  React.useImperativeHandle(ref, () => ({
    focus: () => {
      if (inputEl && inputEl.current) {
        inputEl.current.focus();
      }
    }
  }));
  return (
    <input ref={inputEl} type="text" defaultValue={props.name}/>
  );
}

const FancyInput = React.forwardRef<IFancyInputRef, IFancyInput>(fancyInput);

const App = () => {
  const fancyRef = React.useRef<IFancyInputRef>(null);
  return (
    <div>
      <FancyInput ref={fancyRef} name="icepy" />
      <button onClick={() => {
        if (fancyRef && fancyRef.current) {
          fancyRef.current.focus();
        }
      }}>+</button>
    </div>
  )
}

在组件树之间传递数据的 Context

在一个典型的 React 应用中,数据都是通过 Props 属性自上而下进行传递的,但某些情况下这些属性有多个组件需要共享,那么 Context 就提供了这样一种共享的方式。

当你使用 createContext 创建一个 Context 时它会返回一个 React.Context<T> 类型。

每一个 Context 对象都会返回一个 Provider 组件,它允许消费组件订阅 context 的变化,当 Provider 的value 发生变化时,它内部的所有消费组件都将重新渲染。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IContext {
  name: string;
}
const initContext:IContext = {
  name: "",
};
const Context = React.createContext(initContext);

const AppChild = () => {
  const context  = React.useContext(Context);
  return (
    <div>{context.name}</div>
  )
}

const AppChild1 = () => {
  const context  = React.useContext(Context);
  return (
    <div>{context.name}</div>
  )
}
const App = () => {
  const [ name, setName ] = React.useState("");
  return (
    <div>
      <Context.Provider value={{ name }}>
        <AppChild />
        <AppChild1 />
      </Context.Provider>
    <button onClick={() => {
      setName("icepy");
    }}>+</button>
    </div>
  )
}

我们也可以看一个类组件的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IContext {
  name: string;
}
const initContext:IContext = {
  name: "",
};
const Context = React.createContext(initContext);

class AppChild extends React.Component {
  static contextType = Context;
  public render(){
    const { name } = this.context;
    return (
      <div> { name }</div>
    )
  }
}
const App = () => {
  const [ name, setName ] = React.useState("");
  return (
    <div>
      <Context.Provider value={{ name }}>
        <AppChild />
      </Context.Provider>
      <button onClick={() => {
        setName("icepy");
      }}>+</button>
    </div>
  )
}

在 TypeScript 中 Context 支持的并不算太好,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static contextType?: Context<any>;
/**
 * If using the new style context, re-declare this in your class to be the
 * `React.ContextType` of your `static contextType`.
 *
 * ```ts
 * static contextType = MyContext
 * context!: React.ContextType<typeof MyContext>
 * ```
 *
 * @deprecated if used without a type annotation, or without static contextType
 * @see https://reactjs.org/docs/legacy-context.html
 */
// TODO (TypeScript 3.0): unknown
context: any;

Ref 和 DOM

Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App = () => {
  const but = React.createRef<HTMLButtonElement>();
  return (
    <div>
      <button ref={but} onClick={() => {
        if (but && but.current) {
          if (but.current.nodeName === "BUTTON") {
            alert("BUTTON");
          }
        }
      }}> + </button>
    </div>
  )
}

获取 React 对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class AppChild extends React.Component {

  public onButtonClick = (target: EventTarget) => {
    console.dir(target);
  }

  public render(){
    return (
      <div>1234</div>
    )
  }
}

const App = () => {
  const appChild = React.createRef<AppChild>();
  return (
    <>
      <AppChild ref={appChild}/>
      <button onClick={(ev: React.MouseEvent<HTMLButtonElement>) => {
        if (appChild && appChild.current) {
          appChild.current.onButtonClick(ev.target);
        }
      }}>+</button>
    </>
  )
}

ref 也可以传递函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App = () => {
  const inputCallback = (el: HTMLInputElement) => {
    console.log(el);
  }
  return (
    <div>
      <input ref={inputCallback}/>
    </div>
  )
}

对应的 useRef() 也非常类似,它可以很方便的保存任何可变值,这是因为它创建的是一个普通 JavaScript 对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App = () => {
  const inputEl = React.useRef<HTMLInputElement>(null);
  return (
    <div>
      <input ref={inputEl} type="text"/>
      <button onClick={() => {
        if (inputEl && inputEl.current) {
          inputEl.current.focus();
        }
      }}>+</button>
    </div>
  )
}

React 顶层其他 APIs

React 是整个 React 库的入口,顶层 APIs 中除了我们比较熟悉的如 Component 之外还有一些比较有用的,这里会介绍几种我们不常用但非常重要的顶层 APIs。

isValidElement

验证对象是否为 React 对象,返回值是 truefalse

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
React.isValidElement(object);

cloneElement

有时我们会遇到这样一个场景,就是 tabs 选项卡,对于它的设计我们可能会有一个预期,做一个简单版,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Tabs value={index} onChange={(value) => {
  setIndex(value);
}}>
  <Tab value={1}>Tab 1</Tab>
  <Tab value={2}>Tab 2</Tab>
  <Tab value={3}>Tab 3</Tab>
</Tabs>
<div style={{ display: index === 1 ? "block": "none"}}>1</div>
<div style={{ display: index === 2 ? "block": "none"}}>2</div>
<div style={{ display: index === 3 ? "block": "none"}}>3</div>

点击 Tab 的时候需要把它的 onClick 事件替换成 Tabs 的 onChange,因此这里会使用到 cloneElement 方法来处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface ITabsProps {
  value: number;
  onChange: (value: number) => void;
  children?: React.ReactNode;
}

const tabsStyles: React.CSSProperties = {
  width: "100%",
  display: "flex",
  flexDirection: "row",
}

const Tabs = (props: ITabsProps) => {
  const onChange = (value: number) => {
    props.onChange(value);
  }
  const renderTab = () => {
    const { children } = props;
    if (children && Array.isArray(children)) {
      const arrayChilds = children.map((v, i) => {
        if (React.isValidElement(v)) {
          const childrenProps = {
            onChange,
            key: `Tab-${i}`,
          };
          return React.cloneElement(v, childrenProps);
        }
      });
      return arrayChilds;
    }
    if (children && !Array.isArray(children)) {
      const childrenProps = {
        onChange,
        key: "Tab",
      };
      if (React.isValidElement(children)) {
        return React.cloneElement(children, childrenProps);
      }
    }
  }

  return (
    <div style={tabsStyles}>
      {renderTab()}
    </div>
  );
}

由于我们把 childrenProps 替换了,因此子元素的 Tab 就可以如此:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface ITabProps {
  value: number;
  onChange?: (value: number) => void;
  children?: React.ReactNode;
}

const tabStyles: React.CSSProperties = {
  width: "50px",
  marginRight: "10px",
  border: "1px solid red",
  textAlign: "center",
  cursor: "pointer"
}

const Tab = (props: ITabProps) => {
  const changeHandler = () => {
    const { onChange, value } = props;
    if (onChange) {
      onChange(value);
    }
  }
  return (
    <div
      style={tabStyles}
      onClick={changeHandler}
    >
      { props.children }
    </div>
  );
}

memo

React.memo 为高阶组件。它与 React.PureComponent 非常相似,但它适用于函数组件,但不适用于 class 组件。

此方法仅作为性能优化的方式而存在。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IProps {
  value: number;
}

const AppChild = (props: IProps) => {
  return (
    <div>props.value: { props.value}</div>
  )
}

const MemoAppChild = React.memo(AppChild);

interface IState {
  date: Date;
  value: number;
}

class App extends React.Component<{}, IState> {

  constructor(props: {}){
    super(props);
    this.state = {
      value: 0,
      date: new Date(),
    }
  }

  public componentDidMount(){
    setInterval(()=>{
      this.setState({
        date:new Date()
      })
    },1000)
  }

  public render(){
    return (
      <div>
        <MemoAppChild value={this.state.value} />
        <div>
          { this.state.date.toString() }
        </div>
      </div>
    );
  }
}

如果你想更细节的控制,可以传入第二个参数,它是一个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IProps {
  value: number;
}

const AppChild = (props: IProps) => {
  return (
    <div>props.value: { props.value}</div>
  )
}

type Equal = (prevProps: IProps, nextProps: IProps) => boolean;

const areEqual: Equal = (prevProps, nextProps) => {
  if (prevProps.value === nextProps.value) {
    return true;
  } else {
    return false;
  }
}
const MemoAppChild = React.memo(AppChild, areEqual);

interface IState {
  date: Date;
  value: number;
}

class App extends React.Component<{}, IState> {

  constructor(props: {}){
    super(props);
    this.state = {
      value: 0,
      date: new Date(),
    }
  }

  public componentDidMount(){
    setInterval(()=>{
      this.setState({
        date:new Date()
      })
    },1000)
  }

  public render(){
    return (
      <div>
        <MemoAppChild value={this.state.value} />
        <div>
          { this.state.date.toString() }
        </div>
      </div>
    );
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 子曰五溪 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
React Hooks-useTypescript!
在React v16.8新增了Hook,它提供了在函数组件中访问状态和React生命周期等能力,这些函数可以在程序的各个组件之间复用,达到共享逻辑的目的。
写代码的阿宗
2020/09/22
4.2K0
useTypescript-React Hooks和TypeScript完全指南
React v16.8 引入了 Hooks,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。这些功能可以在应用程序中的各个组件之间使用,从而易于共享逻辑。Hook 令人兴奋并迅速被采用,React 团队甚至想象它们最终将替换类组件。
前端森林
2020/04/23
8.6K0
useTypescript-React Hooks和TypeScript完全指南
React + TypeScript 实践
需要添加额外的配置:"allowSyntheticDefaultImports": true
公众号@魔术师卡颂
2021/05/08
6.5K0
🔖TypeScript 备忘录:如何在 React 中完美运用?
一直以来,ssh 身边都有很多小伙伴对 TS 如何在 React 中运用有很多困惑,他们开始慢慢讨厌 TS,觉得各种莫名其妙的问题降低了开发的效率。
ssh_晨曦时梦见兮
2022/03/09
2.8K0
🔖TypeScript 备忘录:如何在 React 中完美运用?
React+TypeScript使用规范
一个采用 parameterName is Type的形式返回 boolean 值的函数,但 parameterName 必须是当前函数的参数名
用户4619307
2023/05/04
4.7K0
React Hooks教程之基础篇
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
乐圣
2022/11/19
3K0
React-hooks+TypeScript最佳实战
如果新的 state 需要通过使用先前的 state 计算得出,那么可以将回调函数当做参数传递给 setState。该回调函数将接收先前的 state,并返回一个更新后的值。
xiaofeng123aa
2022/10/17
6.2K0
用TypeScript编写React的最佳实践
如今, React 和 TypeScript 是许多开发人员正在使用的两种很棒的技术。但是把他们结合起来使用就变得很棘手了,有时很难找到正确的答案。不要担心,本文我们来总结一下两者结合使用的最佳实践。
ConardLi
2020/06/04
4.8K0
【React】1427- 如何使用 TypeScript 开发 React 函数式组件?
在我们使用 React 开发项目时,使用最多的应该都是组件,组件又分为「函数组件」和「类组件」,我们可以这么定义:
pingan8787
2022/11/15
6.6K0
【React】1427- 如何使用 TypeScript 开发 React 函数式组件?
你要的react+ts最佳实践指南
本文根据日常开发实践,参考优秀文章、文档,来说说 TypeScript 是如何较优雅的融入 React 项目的。
xiaofeng123aa
2022/10/03
3.1K0
面试官:说说如何在React项目中应用TypeScript?
单独的使用typescript 并不会导致学习成本很高,但是绝大部分前端开发者的项目都是依赖于框架的
winty
2021/10/11
7000
面试官:说说如何在React项目中应用TypeScript?
React 进阶 - context
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。必须注意,提供者永远要在消费者上层,正所谓水往低处流,提供者一定要是消费者的某一层父级。
Cellinlab
2023/05/17
4530
React 进阶 - context
[2021-02-24更新]​React Hook使用要点
在官网上,Hook简介的章节里,很安抚性地提到,Hook的提出不旨在替换Class创建组件,而是一种可选、100%向后兼容的特性。然而从使用效果的来说,Hook的应用,解决了render props 和高阶组件组织代码所带来晦涩难懂的窘况,让前端代码代码复用的粒度变得更低,代码可读性更高,研发效率自然也更高。我们团队的新代码,基本都在转向Hook,我也不例外,为了快速翻阅资料,整理以下核心信息,方便高效研发。
zoujunjie202
2022/07/27
6780
Typescript配合React实践
使用ts写React代码写了将近三个月,从刚开始觉得特别垃圾到现在觉得没有ts不行的一些实践以及思考。如果按部就班的写React就体会不到使用ts的乐趣,如果多对代码进行优化,进行重构,在业务中实践比较好的一些方案就会体会到ts真正的乐趣,但是ts也在过程中给我带来了痛苦,在本文的最后会具体展开一下。
前端迷
2019/07/27
9480
typescript实战总结之实现一个互联网黑白墙
笔者上一篇文章 TS核心知识点总结及项目实战案例分析 主要写了typescript的用法和核心知识点总结, 这篇文章将通过一个实际的前端案例来教大家如何在项目中使用typescript.
徐小夕
2020/08/17
1.2K0
typescript实战总结之实现一个互联网黑白墙
深入浅出 React Hooks
Hooks 顾名思义,字面意义上来说就是 React 钩子的概念。通过一个 case 我们对 React Hooks 先有一个第一印象。
桃翁
2019/06/12
2.5K0
可能是你需要的 React + TypeScript 50 条规范和经验
下列关键字后必须有大括号(即使代码块的内容只有一行):if, else, for, while, do, switch, try, catch, finally, with。
夜尽天明
2019/06/17
2.7K0
接着上篇讲 react hook
Hook 是一个特殊的函数,使用了 JavaScript 的闭包机制,可以让你在函数组件里“钩入” React state 及生命周期等特性。Hook 不能在 class 组件中使用。这也就是我开篇说的函数式组件一把索的原因
sunseekers
2020/06/03
2.6K0
探究React的渲染
React本质上是建立用户界面的库。一个公式有助于理解React:view=function(state),或简写为v=f(s)。下一个问题是:React在什么时间、如何更新视图?回答这个问题之前,我们先弄清楚——什么是渲染?
fanzhh
2023/10/16
1980
使用 TypeScript 编写 React.js 应用 | 笔记
在 <ProjectList /> 下方显示加载指示器。仅在 loading=true .
yiyun
2023/07/20
9410
使用 TypeScript 编写 React.js 应用 | 笔记
相关推荐
React Hooks-useTypescript!
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文