欢呼!我们的函数组件已经可以正常工作了 。

文章插图
我们已经完成了很多,让我们深吸一口气,喝杯咖啡,因为我们已经差不多实现了 React,不过我们还需要攻克类组件 。
我们首先在 src/qnd-react.js 中创建 Component 基类:
//src/qnd-react.js import { h } from 'snabbdom'; const createElement = (type, props = {}, ...children) => {//如果是函数组件,那么调用它,并返回执行结果if (typeof (type) == 'function') {return type(props);}return h(type, { props }, children); }; class Component {constructor() { }componentDidMount() { }setState(partialState) { }render() { } } const QndReact = {createElement,Component }; export default QndReact; 现在我们在 src/counter.js 中编写我们的第一个 Counter 类组件:
//src/counter.js import QndReact from './qnd-react'; export default class Counter extends QndReact.Component {constructor(props) {super(props);this.state = {count: 0}}componentDidMount() {console.log('Component mounted');}render() {return <p>Count: {this.state.count}</p>} } 是的,我知道我们尚未在计数器中实现任何逻辑,但是别担心,一旦我们的状态管理系统运行正常,我们就会添加这些内容 。现在,让我们尝试在 src/index.js 中渲染它 。
//src/index.js import QndReact from "./qnd-react"; import QndReactDom from './qnd-react-dom'; import Counter from "./counter"; const Greeting = ({ name }) => <p>Welcome {name}!</p>; const App = (<div><h1 className="primary">QndReact is Quick and dirty react</h1><p>It is about building your own React in 90 lines of JavsScript</p><Greeting name={"Ameer Jhan"} /><Counter /></div> ); QndReactDom.render(App, document.getElementById('root')); 和料想中的一样,又又又报错了 。

文章插图
上面的错误看起来是不是很熟悉,当你尝试使用类组件而不集成自 React.Component 时,可能遇到过以上错误 。要知道为什么会这样,我们可以在 React.createElement(...) 中添加一个 console.log,如下所示:
//src/qnd-react.js import { h } from 'snabbdom'; const createElement = (type, props = {}, ...children) => {console.log(typeof (type), type);//如果是函数组件,那么调用它,并返回执行结果if (typeof (type) == 'function') {return type(props);}return h(type, { props }, children); }; 我们来看看控制台打印了什么内容 。

文章插图
你可以看出 Counter 的 type 类型也是函数,这是因为 Babel 会将 ES6 类转换为普通的 JS 函数,那么我们该如何类组件的情况呢 。其实,我们可以在我们的 Component 基类中添加一个静态属性,这样我们利用该属性去检查 type 参数是否是一个类 。React 中也是相同的处理逻辑,你可以阅读 Dan的博客
//src/qnt-react.js import { h } from 'snabbdom'; const createElement = (type, props = {}, ...children) => {console.log(typeof (type), type);//如果是函数组件,那么调用它,并返回执行结果if (typeof (type) == 'function') {return type(props);}return h(type, { props }, children); }; class Component {constructor() { }componentDidMount() { }setState(partialState) { }render() { } } //给 Component 组件添加静态属性来区分是函数还是类 Component.prototype.isQndReactClassComponent = true; const QndReact = {createElement,Component }; export default QndReact; 现在,我们在 QndReact.createElement(...) 中增加一些代码来处理类组件 。
//src/qnd-react.js import { h } from 'snabbdom'; const createElement = (type, props = {}, ...children) => {console.log(type.prototype);/*** 如果是类组件* 1.创建一个实例* 2.调用实例的 render 方法*/if (type.prototype && type.prototype.isQndReactClassComponent) {const componentInstance = new type(props);return componentInstance.render();}//如果是函数组件,那么调用它,并返回执行结果if (typeof (type) == 'function') {return type(props);}return h(type, { props }, children); }; class Component {constructor() { }componentDidMount() { }setState(partialState) { }render() { } } //给 Component 组件添加静态属性来区分是函数还是类 Component.prototype.isQndReactClassComponent = true; const QndReact = {createElement,Component }; export default QndReact; 现在,我们的类组件已经能够渲染到浏览器上了:

文章插图
我们向类组件中增加 state,在此之前,我们需要知道,每次调用 this.setState({}) 时,如何更新 DOM 的责任是 react-dom 包,而不是 React 的责任 。这是为了使 React 的核心部分,例如Component 类与平台分离,从而提升代码的可重用性 。即在 ReactNative 中,你也可以使用同样的 Component 类,react-native 负责如何更新UI 。你可能会问自己:当调用 this.setState(...) 时,React 如何知道该怎么做,答案就是 react-dom 通过在 React 上设置了一个 __updater 属性与 React 进行通信 。Dan 对此也有出色的文章,你可以点击阅读 。现在让我们在 QndReactDom 中为 QndReact 添加 __updater 属性 。
推荐阅读
- ThinkPHP5任意代码执行分析全记录
- 五峰,多角度广思维构建现代茶产业体系 打造土家生态茶乡
- Swoole简介
- 佳能喷墨打印机报错不能用?看到这些代码这样做立马解决
- php之"EXCEL导出"代码生成器的实现思路
- 运行 JavaScript 代码片段的 20 种工具
- 博士|复旦博士写了130行代码:2分钟搞定繁琐的核酸筛查
- 十五个常见的WordPresswp-config.php设置代码
- 如何优雅的在头条插入代码,介绍几款在线源代码转图片工具
- 暴雪|魔兽正式服:玩家复原暴雪代码,10.0增加新职业,兼顾3个职责?
