乐趣区

关于javascript:React-高级指引的学习笔记-4

动态类型查看

像 Flow 和 TypeScript 等这些动态类型查看器,能够在运行前辨认某些类型的问题。他们还能够通过减少主动补全等性能来改善开发者的工作流程。出于这个起因,咱们倡议在大型代码库中应用 FlowTypeScript 来代替 PropTypes。(引自官网)

在这一大节中,次要讲的就是如何应用 FlowTypeScript 来实现对动态类型的检测,如果我的项目是通过 create-react-app 构建的,那么这两个计划都是曾经可能开箱即用的,只须要新增比较简单的配置即可。如 Flow

// 1、在我的项目中新增 Flow
yarn add --dev flow-bin

// 2、在 package.json 中的 scripts 里退出
"scripts":{
    ...,
    "flow": "flow"
}

// 1、运行 flow
yarn flow

以上就是简略的 Flow 的配置, 只有在我的项目中应用了 //@flow 正文的页面,Flow 就会对该页面进行检测,最初返回是否有异样。随后说的是 TypeScript 的配置:

TypeScript 是一种由微软开发的编程语言。它是 JavaScript 的一个类型超集,蕴含独立的编译器。作为一种类型语言,TypeScript 能够在构建时发现 bug 和谬误,这样程序运行时就能够防止此类谬误。(引自官网)

都晓得,在应用 TS 进行编程的时候是必须要进行类型的定义的,这天然就能在应用的时候就进行验证。create-react-app 曾经配置好了 TS 的运行环境, 能够通过 npx create-react-app my-app --template typescript 进行创立我的项目,如果是在现有的我的项目中新增,须要先装置:yarn add typescript @types/node @types/react @types/react-dom @types/jest。随后将所有 js 类文件重命名,如(src/index.js 替换成 src/index.tsx

PS: 对于本人通过 webpack 进行配置的用户来说,Flow 须要在编译的时候去除其语法,不然会报错:具体配置见 flow-remove-types

严格模式

严格模式有点相似于前文的 Profiler 的用法,不过严格模式是通过 StrictMode 检测外部组件的合法性,目前次要用于一下几项:

  • 辨认不平安的生命周期
  • 对于应用过期字符串 ref API 的正告
  • 对于应用废除的 findDOMNode 办法的正告
  • 检测意外的副作用
  • 检测过期的 context API

(引自官网)

所谓不平安的生命周期次要是针对用于更新的几个生命周期在调用时呈现的异样,在异步渲染之更新这外面进行了形容,在上面的援用中,react 特意对 componentWillMountcomponentWillReceivePropscomponentWillUpdate 设置了以 UNSAFE_ 结尾的别名,可见这些更新在 react 看来是不平安的。此外,在 React17.0 之后将新增生命周期来欠缺现有的更新机制: getDerivedStateFromPropsgetSnapshotBeforeUpdate

从概念上讲,React 分两个阶段工作:

  • 渲染 阶段会确定须要进行哪些更改,比方 DOM。在此阶段,React 调用 render,而后将后果与上次渲染的后果进行比拟。
  • 提交 阶段产生在当 React 利用变动时。(对于 React DOM 来说,会产生在 React 插入,更新及删除 DOM 节点的时候。)在此阶段,React 还会调用 componentDidMountcomponentDidUpdate 之类的生命周期办法。

提交阶段通常会很快,但渲染过程可能很慢。因而,行将推出的 concurrent 模式 (默认状况下未启用) 将渲染工作合成为多个局部,对工作进行暂停和复原操作以防止阻塞浏览器。这意味着 React 能够在提交之前屡次调用渲染阶段生命周期的办法,或者在不提交的状况下调用它们(因为呈现谬误或更高优先级的工作使其中断)。

渲染阶段的生命周期包含以下 class 组件办法:

  • constructor
  • componentWillMount (or UNSAFE_componentWillMount)
  • componentWillReceiveProps (or UNSAFE_componentWillReceiveProps)
  • componentWillUpdate (or UNSAFE_componentWillUpdate)
  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • setState 更新函数(第一个参数)

因为上述办法可能会被屡次调用,所以不要在它们外部编写副作用相干的代码,这点十分重要。疏忽此规定可能会导致各种问题的产生,包含内存透露和或呈现有效的应用程序状态。可怜的是,这些问题很难被发现,因为它们通常具备非确定性。

严格模式不能自动检测到你的副作用,但它能够帮忙你发现它们,使它们更具确定性。通过成心反复调用以下函数来实现的该操作:

  • class 组件的 constructorrender 以及 shouldComponentUpdate 办法
  • class 组件的生命周期办法 getDerivedStateFromProps
  • 函数组件体
  • 状态更新函数 (即 setState 的第一个参数)
  • 函数组件通过应用 useStateuseMemo 或者 useReducer

(以上引自官网)

应用 PropTypes 类型查看

这一个模块就是说了 PropTypes 怎么在 react 中应用,以及大部分的断定函数是如何书写的,因为类型太多我就不复制黏贴了,前面如果想要晓得就去官网本人看就行,下面的题目是中转链接

非受控组件

对于一个承受参数并返回相应后果的组件来说,分为非受控组件和受控组件,其参数也分为受控参数和非受控参数。以 antd4.0 为例来看,defaultValue 这一参数基本上都是 非受控 的,而 value 则是 受控 的,你在外层能够管制外部的函数渲染,外层的更改会传递到外部进行批改。
通常来说,应用 setState 还是应用 ref 来取得数据,次要还是依据以后的需要来决定的,如果你不须要动静的更新,则应用 ref 就很不便,反之亦然,上面写了一个感觉是假的非受控组件的 form 表单,模拟 antdForm, 用到了高级指引中学到的几种办法以及 React.Children:

/**
 * @desc 用于测试 NotContral 的页面
 * @name NotContral
 * @author Cyearn
 * @date 2020/11/21
 */

import React, {Component} from "react";
import styles from "./styles.module.less";

class NotContral extends Component {constructor(props) {super(props);
    this.state = {};
    this.ref = React.createRef();}
  componentDidMount() {}
  submit = () => {const { setValue, getValue} = this.ref;
    console.log(getValue());
  };
  render() {
    return (<div className={styles.contain}>
        <Form refForm={(el) => (this.ref = el)}>
          <Item label={"账号"} name={"username"}>
            <Input />
          </Item>
          <Item label={"明码"} name={"password"}>
            <Input />
          </Item>
        </Form>
        <button onClick={this.submit}> 提交 </button>
      </div>
    );
  }
}
const Form = function (props) {const { children, refForm} = props;

  const ReForm = withForm(children, refForm);
  return (
    <div>
      test
      <ReForm ref={refForm} />
    </div>
  );
};

function withForm(children, refForm) {if (children) {
    return class extends Component {constructor(props) {super(props);
        this.state = {};}

      componentDidMount() {let param = {};
        // 向子组件注入默认值,onChange 事件
        this.Children = React.Children.map(children, (child) => {param[child.props.name] = "";
          let key = child.props.name;
          return React.cloneElement(child, {
            onChange: this.changeInput,
            defaultValue: this.state[key],
            value: this.state[key],
          }); // 这次咱们通过 React.cloneElement 增加属性
        });
        this.setState({...param,});
      }
      // 定义设置值得函数
      setValue = (obj = {}) => {
        this.setState({...obj,});
      };
      // 定义获取值得函数
      getValue = () => {
        const all = this.state;
        return {...all};
      };
      // 当表单内数据发生变化的函数
      changeInput = (e, id) => {let param = {};
        param[id] = e;
        this.setState({...param,});
      };

      onValueChange = () => {};

      render() {return <form onValueChange={this.onValueChange}>{this.Children}</form>;
      }
    };
  }
}

// HOC
function WithItem(Inject, props) {
  class Test extends Component {constructor(props) {super(props);
      this.state = {value: ""};
    }
    render() {const { value} = props;
      console.log(value);
      return (
        <Inject
          {...props}
          onChange={(e) => props.onChange(e, props.name)}
          value={value}
        />
      );
    }
  }
  return Test;
}

// 包裹子节点
class Item extends Component {constructor(props) {super(props);
    this.state = {};}
  render() {const { label, children, ...other} = this.props;
    let type = children && children.type;
    if (type) {const Children = WithItem(this.props.children.type, { ...other});
      return (<section style={{ marginBottom: 10}}>
          <span>{label}:</span>
          <Children />
        </section>
      );
    } else {return null;}
  }
}

// 最小节点
function Input(props) {const { onChange, value} = props;
  return (
    <input
      type="text"
      onChange={(e) => onChange(e.target.value)}
      value={value}
    />
  );
}

export default NotContral;
退出移动版