# React+Typescript

By [cxy666](https://paragraph.com/@cxy666) · 2022-02-08

---

函数组件

    //推荐使用✅ better
    const WrapComponent: React.FC<ExtendedProps> = (props) => {
    // return ...
    };
    //直接使用
    export default WrapComponent;
    
    // 或者
    export default function (props: React.PropsWithChildren<SpinProps>) {
    // return ...
    }
    

    const Notice: React.FC = () => {}
    

### forms

    port * as React from 'react'
    
    type changeFn = (e: React.FormEvent<HTMLInputElement>) => void
    
    const App: React.FC = () => {
    
    const [state, setState] = React.useState('')
    
    const onChange: changeFn = e => {
    setState(e.currentTarget.value)
    }
    ✅ better
    const onSubmit = (e: React.SyntheticEvent) => {
    e.preventDefault()
    const target = e.target as typeof e.target & {
    password: { value: string }
    } // 类型扩展
    const password = target.password.value
    }
    
    return (
    <form onSubmit={onSubmit}>
    <input type="text" value={state} onChange={onChange} />
    </form>
    )
    
    }
    

React Hook
----------

_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。

### useState

*   调用`useState()` Hook 来启用函数组件中的状态。
    
*   `useState(initialValue)`的第一个参数`initialValue`是状态的初始值。
    
*   `[state, setState] = useState(initialValue)`返回一个包含`2`个元素的数组:状态值和状态更新函数。
    
*   使用新值调用状态更新器函数`setState(newState)`更新状态。或者，可以使用一个回调`setState(prev => next)`来调用状态更新器，该回调将返回基于先前状态的新状态。
    
*   调用状态更新器后，React 确保重新渲染组件，以使新状态变为当前状态。
    
    demo:按按钮新增灯泡或者开关灯
    
*   import React, { useState } from 'react'; function Bulbs() { const \[on, setOn\] = useState(false); const \[count, setCount\] = useState(1); const lightSwitch = () => setOn(on => !on); const addBulbs = () => setCount(count => count + 1); const bulb = <div className={on ? 'bulb-on' : 'bulb-off'} />; const bulbs = Array(count).fill(bulb); return ( <> <div className="bulbs">{bulbs}</div> <button onClick={lightSwitch}>开/关</button> <button onClick={addBulbs}>添加灯泡</button> </> ); }
    

    //给定初始化值情况下可以直接使用
    
    import { useState } from 'react';
    // ...
    const [val, toggle] = useState(false);
    // val 被推断为 boolean 类型
    // toggle 只能处理 boolean 类型
    
    
    //没有初始值（undefined）或初始 null
    
    type AppProps = { message: string };
    const App = () => {
        const [data] = useState<AppProps | null>(null);✅ better
        // const [data] = useState<AppProps | undefined>();
        return <div>{data?.message}</div>;
    };
    

### useEffect

你之前可能已经在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”，或者简称为“作用”。

`useEffect` 就是一个 Effect Hook，给函数组件增加了操作副作用的能力。它跟 class 组件中的 `componentDidMount`、`componentDidUpdate` 和 `componentWillUnmount` 具有相同的用途，只不过被合并成了一个 API。（我们会在[使用 Effect Hook](https://react-1251415695.cos-website.ap-chengdu.myqcloud.com/docs/hooks-effect.html) 里展示对比 `useEffect` 和这些方法的例子。）

可以把 `useEffect` Hook 看做 `componentDidMount`，`componentDidUpdate` 和 `componentWillUnmount` 这三个函数的组合。

*   只能在**函数最外层**调用 Hook。不要在循环、条件判断或者子函数中调用。
    
*   只能在 **React 的函数组件**中调用 Hook。不要在其他 JavaScript 函数中调用。
    

下面这个组件在 React 更新 DOM 后会设置一个页面标题：

    import React, { useState, useEffect } from 'react';
    
    function Example() {
      const [count, setCount] = useState(0);
    
      // 相当于 componentDidMount 和 componentDidUpdate:
      useEffect(() => {
        // 使用浏览器的 API 更新页面标题
        document.title = `You clicked ${count} times`;
      });
    
      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>
      );
    }
    

当你调用 `useEffect` 时，就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的，所以它们可以访问到组件的 props 和 state。默认情况下，React 会在每次渲染后调用副作用函数 —— **包括**第一次渲染的时候。

---

*Originally published on [cxy666](https://paragraph.com/@cxy666/react-typescript)*
