随缘补刀

随缘补刀 个人博客:随便写写...

React 父子组件生命周期触发顺序

生命周期函数 父组件 子组件
UNSAFE_componentWillMount 1 2
getDerivedStateFromProps 1 2
componentDidMount 2 1
shouldComponentUpdate 1 2
getSnapshotBeforeUpdate 2 1
componentDidUpdate 2 1
componentWillUnmount 1 2

父子组件生命周期log日志

child    getDerivedStateFromProps    父组件触发 getDerivedStateFromProps
Grandson getDerivedStateFromProps    子组件触发 getDerivedStateFromProps
child    UNSAFE_componentWillMount   父组件触发 UNSAFE_componentWillMount
Grandson UNSAFE_componentWillMount   子组件触发 UNSAFE_componentWillMount
Grandson componentDidMount           子组件触发 componentDidMount
child    componentDidMount           父组件触发 componentDidMount
child    getDerivedStateFromProps    父组件触发 getDerivedStateFromProps
child    shouldComponentUpdate       父组件触发 shouldComponentUpdate
Grandson getDerivedStateFromProps    子组件触发 getDerivedStateFromProps
Grandson shouldComponentUpdate       子组件触发 shouldComponentUpdate
Grandson getSnapshotBeforeUpdate     子组件触发 getSnapshotBeforeUpdate
child    getSnapshotBeforeUpdate     父组件触发 getSnapshotBeforeUpdate
Grandson componentDidUpdate          子组件触发 componentDidUpdate
child    componentDidUpdate          父组件触发 componentDidUpdate
child    componentWillUnmount        父组件触发 componentWillUnmount
Grandson componentWillUnmount        子组件触发 componentWillUnmount

react props.children 探索

总结

props.children的数据类型包括:

  • undefined
  • string
  • object (ReactElement)
  • function
  • array: (string|ReactElement|function)[]

undefind

import React from "react";

class Child extends React.Component {
  render() {
    const { children } = this.props;
    console.log("children: ", typeof children, children); // children:  'undefined' undefined
    return <div className="child">{children}</div>;
  }
}

export default function App() {
  return (
    <div>
      <Child></Child>
    </div>
  );
}

string

import React from "react";

class Child extends React.Component {
  render() {
    const { children } = this.props;
    console.log("children: ", typeof children, children); // children:  'string' 131231
    return <div className="child">{children}</div>;
  }
}

export default function App() {
  return (
    <div>
      <Child>131231</Child>
    </div>
  );
}

object

import React from "react";

class Child extends React.Component {
  render() {
    const { children } = this.props;
    console.log("children: ", typeof children, children); // children:  'object'  {$$typeof: Symbol(react.element), key: null, ref: null, props: {…}, type: ƒ, …}
    return <div className="child">{children}</div>;
  }
}

function Doll() {
  return <div>This is a doll;</div>;
}

export default function App() {
  return (
    <div>
      <Child>
        <Doll/>
      </Child>
    </div>
  );
}

function

import React from "react";

class Child extends React.Component {
  render() {
    const { children, name } = this.props;
    console.log("children: ", typeof children, children); // children:  'function' arg1 => { return "hello " + arg1; }
    return <div className="child">{children(name)}</div>;
  }
}

export default function App() {
  return (
    <div>
      <Child name="Tom">
        {(arg1) => {
          return "hello " + arg1;
        }}
      </Child>
    </div>
  );
}

array

import React from "react";
console.log(React);

class Child extends React.Component {
  render() {
    const { children, name } = this.props;
    console.log(
      "children: ",
      typeof children, // 'object'
      children instanceof Array, // true
      children // [ƒ, "This is a Text;", {…}]
    );
    return (
      <div className="child">
        {children[0](name)}
        <br/>
        {React.Children.map(children, (v, i) => {
          console.log('--->', typeof v, v, i); // 这里需要注意,React.Children.map函数会先过滤掉数组中的function类型数据
          if (typeof v === "function") {
            return v(name);
          } else {
            return v;
          }
        })}
      </div>
    );
  }
}

function Doll() {
  return <div>This is a doll;</div>;
}

export default function App() {
  return (
    <div>
      <Child name="Tom">
        {(arg1) => {
          return "hello " + arg1;
        }}
        This is a Text;
        <Doll />
      </Child>
    </div>
  );
}

Proxy 和 defineProperty 的比较

可拦截属性的比较

属性 defineProperty Proxy 描述
get 支持 支持 (target, propKey, receiver)
拦截对象属性的读取,比如 proxy.foo 和proxy[‘foo’]。
set 支持 支持 (target, propKey, value, receiver)
拦截对象属性的设置,比如proxy.foo = v 或 proxy[‘foo’] = v,返回一个布尔值。
has 不支持 支持 (target, propKey)
拦截 propKey in proxy 的操作,返回一个布尔值。
deleteProperty 不支持 支持 (target, propKey)
拦截 delete proxy[propKey] 的操作,返回一个布尔值。
ownKeys 不支持 支持 (target)
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys() 的返回结果仅包括目标对象自身的可遍历属性。
getOwnPropertyDescriptor 不支持 支持 (target, propKey)
拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty 不支持 支持 (target, propKey, propDesc)
拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
preventExtensions 不支持 支持 (target)
拦截 Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf 不支持 支持 (target)
拦截 Object.getPrototypeOf(proxy),返回一个对象。
isExtensible 不支持 支持 (target)
拦截 Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf 不支持 支持 (target, proto)
拦截 Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
apply 不支持 支持 (target, object, args)
拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
construct 不支持 支持 (target, args)
拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)。

## 兼容性的比较 ### proxy的兼容性如下
desktopmobileserver
ChromeEdgeFirefoxInternet ExplorerOperaSafariWebView AndroidChrome AndroidFirefox for AndroidOpera AndroidSafari on iOSSamsung InternetNode.js
Proxy
Proxy() constructor
revocable

### defineProperty兼容性如下
desktopmobileserver
ChromeEdgeFirefoxInternet ExplorerOperaSafariWebView AndroidChrome AndroidFirefox for AndroidOpera AndroidSafari on iOSSamsung InternetNode.js
defineProperty

使用总结

  • Object.defineProperty 并非不能监控数组下标的变化(vue2中不能通过下标的方式更新数组)
  • Object.defineProperty 对属性的劫持需要深度遍历,新增属性需要手动Observe
  • Proxy 可以使用业务场景和支持的API更多和全面
  • Proxy 作为新标准,后续会有持续的性能优化
  • Proxy 兼容性是硬伤,在对兼容性有要求的业务场景下无法使用

迁移流程

  1. 在github上新建blog仓库,将博客的仓库推送过去(git remote 的相关操作)
方法一:
git remote rm origin
git remote add origin [url]

方法二
git remote set-url origin [url]
  1. 修改_config.yaml文件,更新仓库地址、发布分支置为gh-pages以及下面的子目录配置
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://xxx.github.io/blog
root: /blog/

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: git
  repo: git@github.com:xxx/blog.git
  branch: gh-pages
  1. 在github上的blog仓库中进行github pages的设置,发布分支置为gh-pages,目录为/(root)
  2. 由于使用github actions进行博客编译,需要设置一些变量,页面路径Settings->Secret,进行参数同步

指定github actions执行环境的node版本

很久没写blog了,最近写了个每日疫情的图表demo,发现使用github actions去更新blog失败,排查过程:

  • 推送blog源代码,能正常触发github actions的操作流程,未出现报错
  • 浏览器打开博客地址,发现reponse的数据为空
  • github切换到博客项目的相应分支,文件都存在,貌似很正常,但是文件的size都为0
  • 本地推送hexo编译好的内容是可以正常更新blog,浏览器打开为正常
  • 怀疑是github actions中配置的环境问题,对比下发现node版本不同,本地12.x/actions中14.x (github actions中默认使用的最新的,时间久了,就存在本地和actions中node版本存在差异的情况)
  • 更新github actions中的配置,设置node版本为12.x,推送代码,博客展示正常
  • 故可以确定是某个依赖在node14.x的环境下无法正常工作导致的异常


下面附上在github actions中设置node版本的方法
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  deploy:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest]
        node-version: [12]

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - uses: actions/checkout@v2
    
    # 这里指定node版本
    - name: Setup node 12
      uses: actions/setup-node@v2
      with:
        node-version: 12.x

    # check env version
    - name: check node version
      run: node --version
    
    - name: check npm version
      run: npm --version

更新每日疫情数据

工作重点
  • 查看echart的相关api
  • 如何获取每日疫情数据(使用node执行js脚本,配合github的actions定时任务完成)
  • 整合数据和图表,形成完整的功能

疫情每日数据demo地址

持续集成(Continuous integration)

频繁地向一个共享仓库提交少量代码变更的软件开发实践。 使用 GitHub Actions,可以创建自定义的 CI 工作流,以自动构建并测试你的代码。 从你的仓库中,你可以查看代码变更的状态和工作流中每个操作的详细日志。 CI 通过提供代码变更的及时反馈来更快地检测并解决 bugs,从而节省开发人员的时间。

持续部署(Continuous deployment)

持续部署建立在持续集成的基础上。 当提交新代码和通过你的 CI 测试时,代码将自动部署到生产环境中。 使用 GitHub Actions,可以创建自定义的 CD 工作流,以便从你的仓库自动部署代码到任何云、自托管服务或平台。 CD 通过自动化部署过程节省开发人员的时间,并更快地向你的客户部署经过测试的、稳定的代码变更。

GitHub Actions 的一些术语

  • workflow (工作流程)
    持续集成一次运行的过程,就是一个 workflow

  • job (任务)
    一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务

  • step(步骤):
    每个 job 由多个 step 构成,一步步完成。 一个工作中的每个步骤都在相同的虚拟环境中执行,从而允许使用文件系统共享信息

  • action (动作):
    每个 step 可以依次执行一个或多个命令(action)。 你可以创建自己的action、使用 GitHub 社区共享的action

理解

上述的内容是任务的组成,以及可以达成的目标

  • 监听到git事件时,可手动或自动执行任务(编译、测试、打包、部署等)
  • 设置为定时任务,自动执行

使用该功能可以实现的功能:

  • 完成项目的打包、编译、部署
  • 定时发送天气邮件
  • 定时发送小说的更新章节

命令工具

// init
npm install -g hexo-cli
hexo init hexo-blog
cd hexo-blog
npm install

// 多端使用
npm install -g hexo-cli
git clone git@github.com:aih8/aih8.github.io.git --depth=1
cd aih8.github.io
npm i

// localhost server on 4200
npm start

// deploy && git update hexo branch
npm run build
0%