React Native入门基础篇(二)

导读

前端发展从早期的切图仔标签到现在的工程化,发展之迅猛的同时也面临着与C/S程序一样的问题,也就是系统化、模块化、规范化,经历过前端百家齐鸣的盛世,js前端在市场的影响力也越来越大,云端化催动着大批C/SB/S的趋势,虚拟domnode生态js工程师可以应用到桌面程序、移动原生应用、小程序、各种物流网嵌入式软件中,大有能用js编写的终会用js,连当时全球风靡的热播剧西部世界里头机器人的源码也有js,场景是这样的:剧中host(机器人)老鸨梅芙,突然发现了自己的身份,于是胁迫人类作业员,并招募其它host,计划逃出这个虚拟世界,却发现自己所有的行动仍然是代码编写出来的,于是就有了下面的剧照


我大js一统江湖啊,连人工智能也靠它写

好吧,以上有些吹水了。玩笑归玩笑,但是我还是想说一句话不管什么语言都要靠生态去推动,reactNative与wexx众多js跨端框架和Flutter这种究竟选哪个好,我个人观点比较看好js .逃)

应用程序的复杂程度越来越大,那么我们也有一个刚需需要面对如果对代码进行复用,在react和vue有一个Mixin(混入)这个术语,这篇我们来聊聊react中的mixin

mixin

先让我们看看在react中是如何使用的

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};

var createReactClass = require('create-react-class');

var TickTock = createReactClass({
  mixins: [SetIntervalMixin], // 使用 mixin
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // 调用 mixin 上的方法
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for {this.state.seconds} seconds.
      </p>
    );
  }
});

ReactDOM.render(
  <TickTock />,
  document.getElementById('example')
);

从上面我们就可以看出该react是对mixins这个参数名对象进行了封装,用当前组件可以使用SetIntervalMixin对象里的参数对象,看起来好像只是两个对象拼装,我们来简单的实现下。

首先要定义一个名叫mixins的函数,它是用来做混入的,接收一个参数list.

// 混入函数
function mixin(mixins: Function[]) {
    return (target: any) => {
        // 判断混入list是否为空
        if (!mixins.length) {
            console.warn(`混入对象是个空的,它必须是需要有值的`, );
            return;
        }
        mixins.forEach((mixinsItem: Function) => {
            // 获取对象里元素描述符
            let descriptors = handleGetOwnPropertyDescriptor(mixinsItem);
            // 将混入集合注入到目标对象的原型链里
            Object.keys(descriptors).forEach((key:string) => {
                defineProperty(target.prototype, key, descriptors[key]);
            })
        })
    }
}

然后我们就可以愉快的使用了。

// 主函数
@mixin([
    timeTools,
    weatherTool,
])
class Main {
    run: Function;
    handle: Function;
    title: string;
}

完整代码如下:

const {
    defineProperty,
    getOwnPropertyDescriptor,
} = Object;

// 混入函数
function mixin(mixins: Function[]) {
    return (target: any) => {
        // 判断混入list是否为空
        if (!mixins.length) {
            console.warn(`混入对象是个空的,它必须是需要有值的`, );
            return;
        }
        mixins.forEach((mixinsItem: Function) => {
            // 获取对象里元素描述符
            let descriptors = handleGetOwnPropertyDescriptor(mixinsItem);
            // 将混入集合注入到目标对象的原型链里
            Object.keys(descriptors).forEach((key:string) => {
                defineProperty(target.prototype, key, descriptors[key]);
            })
        })
    }
}
// 时间
const timeTools:any = {
    title: '时间',
    run() {
        console.log(`${this.title}:进行输出`)
    }
}
// 天气
const weatherTool:any = {
    name: '天气',
    handle() {
        console.log(`${this.name}:进行输出`)
    }
}
// 主函数
@mixin([
    timeTools,
    weatherTool,
])
class Main {
    run: Function;
    handle: Function;
    title: string;
}

const app = new Main();
app.run(); // log->时间:进行输出
app.handle(); // log->天气:进行输出

// 获取对象描述符
function handleGetOwnPropertyDescriptor(obj: Function):object {
    let descriptors = {};
    let keys = Object.keys(obj);
    keys.forEach(key => {
        descriptors[key] = getOwnPropertyDescriptor(obj, key);
    });

    return descriptors;
}

react里的mixin如果组件拥有多个 mixins,且这些 mixins 中定义了相同的生命周期方法(例如,当组件被销毁时,几个 mixins 都想要进行一些清理工作),那么这些生命周期方法都会被调用的。使用 mixins 时,mixins 会先按照定义时的顺序执行,最后调用组件上对应的方法。和我们刚刚实现并没有对此处理,会覆盖调,大体实现思路是这样。

mixin的缺点

  • 如果组件中含有多个mixin,不同的mixin中含有相同名字的非生命周期函数,React会抛出异常(不是后面的函数覆盖前面的函数)。
  • 组件中含有多个mixin,不同的mixin中含有相同名字的生命周期函数,不会抛出异常,mixin中的相同的生命周期函数(除render方法)会按照createClass中传入的mixins数组顺序依次调用,全部调用结束后再调用组件内部的相同的声明周期函数。
  • 组件中含有多个mixin,不同的mixin中的默认props或初始state中不存在相同的key值时,则默认props和初始state都会被合并。
  • 组件中含有多个mixin,不同的mixin中默认props或初始state中存在相同的key值时,React会抛出异常。

HOC

因为mixin存在的问题,react也提出用HOC(高阶组件)的形式可进行替代,大概的思路就是定义一个HOC对象,将目标组件以参数形式传入,HOC相当于一个设计模式,例子如下:

// 此函数接收一个组件...
function withSubscription(WrappedComponent, selectData) {
  // ...并返回另一个组件...
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ...负责订阅相关的操作...
      DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
      DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      // ... 并使用新数据渲染被包装的组件!
      // 请注意,我们可能还会传递其他属性
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

HOC的出现可以解决这些问题:

  • 高阶组件就是一个没有副作用的纯函数,各个高阶组件不会互相依赖耦合
  • 高阶组件也有可能造成冲突,但我们可以在遵守约定的情况下避免这些行为
  • 高阶组件并不关心数据使用的方式和原因,而被包裹的组件也不关心数据来自何处。高阶组件的增加不会为原组件增加负担。

HOC缺陷:

  • HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套,这让调试变得非常困难。
  • HOC可以劫持props,在不遵守约定的情况下也可能造成冲突。

Hooks

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。一个简单例子看看它:

import React, { useState } from 'react';

function Example() {
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容