函数组件

class 组件只接受一个 props ,没有其他逻辑,可以使用函数组件

  • 纯函数,输入 props ,输出 JSX
  • 没有实例,没有生命周期,没有 state
  • 不能扩展其他方法

非受控组件(相对于受控组件

  • ref
    • input 的值不受 state 的控制,只是赋了个默认的初始值 ```jsx import React, { LegacyRef } from “react”;

interface Props {}

interface StateType { count: number; name: string; }

export class Header extends React.Component { private readonly nameRef: React.RefObject; constructor(props: Props) { super(props);

  1. this.state = {
  2. count: 0,
  3. name: "jesse",
  4. };
  5. this.nameRef = React.createRef();
  6. this.handleClick = this.handleClick.bind(this);

}

handleClick() { const elem = this.nameRef.current; console.log(elem.value); }

render() { const { name } = this.state; return (

{/ 使用 defaultValue ,而不是 value ,使用 ref /} {/ state 不会随着改变 /} state.name: {name}
); } }

  1. - defaultValuedefaultChecked
  2. - 手动操作 DOM 元素
  3. 使用场景<br />必须要 DOM 操作,setState 实现不了,使用非受控组件<br />文件上传:`<input type="file">`<br />富文本编辑器,需要传入 DOM 元素
  4. <a name="5VGKX"></a>
  5. #### Portals
  6. 传送门<br />让组件渲染到父组件之外
  7. ```jsx
  8. import React from "react";
  9. import ReactDOM from "react-dom";
  10. interface Props {}
  11. interface StateType {}
  12. export class B extends React.Component<Props, StateType> {
  13. constructor(props: Props) {
  14. super(props);
  15. this.state = {};
  16. }
  17. render() {
  18. return ReactDOM.createPortal(
  19. // {this.props.children} 类似于 vue 的 slot
  20. <div className="b-modal">{this.props.children}</div>,
  21. document.body
  22. );
  23. }
  24. }

使用场景

  • overflow: hidden
  • 父组件的 z-index 值大小
  • fixed 需要放在 body 第一层级

context

上下文

  1. import { Button } from "antd";
  2. import React from "react";
  3. import ReactDOM from "react-dom";
  4. interface Props {}
  5. interface StateType {
  6. theme: string;
  7. }
  8. const ThemeContext = React.createContext("light");
  9. // 函数式组件
  10. function ThemeLink(props: Props) {
  11. return (
  12. <ThemeContext.Consumer>
  13. {(value) => <p>link theme is {value}</p>}
  14. </ThemeContext.Consumer>
  15. );
  16. }
  17. class ThemeButton extends React.Component {
  18. // 写法1:指定 contextType
  19. static contextType = ThemeContext;
  20. render() {
  21. const theme = this.context;
  22. return (
  23. <div>
  24. <p>button theme is {theme}</p>
  25. </div>
  26. );
  27. }
  28. }
  29. // 写法2:指定 contextType
  30. // ThemeButton.contextType = ThemeContext;
  31. function ToolBar(props: Props) {
  32. return (
  33. <div>
  34. <ThemeButton />
  35. <ThemeLink />
  36. </div>
  37. );
  38. }
  39. export class C extends React.Component<Props, StateType> {
  40. constructor(props: Props) {
  41. super(props);
  42. this.state = {
  43. theme: "light",
  44. };
  45. }
  46. changeTheme = () => {
  47. this.setState({
  48. theme: this.state.theme === "light" ? "dark" : "light",
  49. });
  50. };
  51. render() {
  52. const { theme } = this.state;
  53. return (
  54. <ThemeContext.Provider value={theme}>
  55. <ToolBar />
  56. <hr />
  57. <Button onClick={this.changeTheme}>change theme</Button>
  58. </ThemeContext.Provider>
  59. );
  60. }
  61. }

使用场景

  • 主题
  • 语言
  • 认证的用户

异步组件

  • import()
  • React.lazy
  • React.Suspence ```jsx const C = React.lazy(() => import(“components/header/context”));

loading…}>

  1. <a name="wNhoE"></a>
  2. #### 性能优化(对 React 更加重要)
  3. - `SCU`
  4. react 为什么不内部作对比,而是通过 SCU 去让用户做操作?
  5. - 重点:react 默认:父组件更新,子组件无条件更新!
  6. - 避免不规范的写法,或者违反了不可变值
  7. SCU 一定要每次都用吗?
  8. - 需要才优化
  9. SCU 默认返回 true , react 默认重新渲染所有组件<br />必须配合不可变值一起使用<br />有性能问题,再考虑使用
  10. ```jsx
  11. shouldComponentUpdate(
  12. nextProps: Readonly<Props>,
  13. nextStates: Readonly<StateType>
  14. ): boolean {
  15. if (nextStates.theme !== this.state.theme) {
  16. // 可以渲染
  17. return true;
  18. }
  19. // 不重复渲染
  20. return false;
  21. }
  • PureComponentReact.memo
    • 纯组件
    • SCU 实现浅比较
    • 尽量不要做深度比较
    • React.PureComponent
    • 函数式组件 React.memo
  • 不可变值 [immutable.js](https://immutable-js.com/)

HOC 高阶组件

就是一个函数,接收一个组件作为参数,返回一个新的函数。
工厂模式
模式简单,增加组件层级

  1. import React from "react";
  2. interface HOCProps {
  3. x: number;
  4. y: number;
  5. }
  6. const withMouse = <P extends HOCProps>(Component: React.ComponentType<P>) => {
  7. class HOC extends React.Component {
  8. constructor(props: P) {
  9. super(props);
  10. this.state = { x: 0, y: 0 };
  11. }
  12. onMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
  13. this.setState({
  14. x: event.clientX,
  15. y: event.clientY,
  16. });
  17. };
  18. render() {
  19. return (
  20. <div style={{ height: "100px" }} onMouseMove={this.onMouseMove}>
  21. {/* 透传所有 props , 增加 mouse 属性 */}
  22. <Component {...(this.props as P)} mouse={this.state} />
  23. </div>
  24. );
  25. }
  26. }
  27. return HOC;
  28. };
  29. const Mouse = (props: any) => {
  30. const { x, y } = props.mouse;
  31. return (
  32. <div style={{ height: "100px" }}>
  33. <h1>
  34. x: {x}, y: {y}
  35. </h1>
  36. </div>
  37. );
  38. };
  39. export default withMouse(Mouse);

Render Props

通过一个函数将 class 组件中的 state 作为 props 传递给纯函数式组件
代码简洁,学习成本高

  1. import React from "react";
  2. interface State {
  3. x: number;
  4. y: number;
  5. }
  6. interface Props {
  7. render: (state: State) => JSX.Element
  8. }
  9. class Mouse extends React.Component<Props, State> {
  10. constructor(props: Props) {
  11. super(props);
  12. this.state = { x: 0, y: 0 };
  13. }
  14. onMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
  15. this.setState({
  16. x: event.clientX,
  17. y: event.clientY,
  18. });
  19. };
  20. render() {
  21. return (
  22. <div style={{ height: "100px" }} onMouseMove={this.onMouseMove}>
  23. {/* 将 state 作为 props 传递给 render 函数 */}
  24. {this.props.render(this.state)}
  25. </div>
  26. );
  27. }
  28. }
  29. // Mouse.propTypes = {
  30. // render: PropTypes.func.isRequired,
  31. // };
  32. const Ap = () => (
  33. <div style={{ height: "100px" }}>
  34. <Mouse
  35. // render 是一个函数组件
  36. render={({ x, y }: State) => (
  37. <h1>
  38. mouse position is x: {x}, y: {y}
  39. </h1>
  40. )}
  41. />
  42. </div>
  43. );
  44. export default Ap