![](https://img.haomeiwen.com/i8207483/a47cd54d99c5c0ee.png)
今天我们来分析一下 React 的源码,以及在 React 中应用了那些 ES6 的新特性。
首先感谢 Nir Kaufman 大神的分享,最近看了他分享 Redux Pattern 受益匪浅。
![](https://img.haomeiwen.com/i8207483/4764f69e1cadf40f.jpg)
下面代码想必大家不会陌生,我们通过
createElement
方法来创建 create 元素,在 create 我们并没有找到 document 来对应于createElement
来创建元素。
class App extends Component {
render() {
return (
React.createElement('h1',null,"hello react")
)
}
}
ReactDom.render(
React.createElement(App,null),
document.getElementById('app')
)
通过ReactElement
方法来创建一个 react 的 element 元素,通过分析ReactElement
下面的源码,返回一个 element 对象,下面是其源码。
var ReactElement = function (type, key, ref, self, source, owner, props) {
var element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner
};
{
// The validation flag is currently mutative. We put it on
// an external backing store so that we can freeze the whole object.
// This can be replaced with a WeakMap once they are implemented in
// commonly used development environments.
element._store = {};
// To make comparing ReactElements easier for testing purposes, we make
// the validation flag non-enumerable (where possible, which should
// include every environment we run tests in), so the test framework
// ignores it.
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: false
});
// self and source are DEV only properties.
Object.defineProperty(element, '_self', {
configurable: false,
enumerable: false,
writable: false,
value: self
});
// Two elements created in two different places should be considered
// equal for testing purposes and therefore we hide it from enumeration.
Object.defineProperty(element, '_source', {
configurable: false,
enumerable: false,
writable: false,
value: source
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
};
通过 React.createElement 创建元素 el 后,我们尝试修改 el 的 myName 属性。
class App extends Component{
render(){
const el = React.createElement('h1',null,"hello react")
el.myName = 'zidea';
console.log(el);
return el;
// return (
// <div>
// <Greeting/>
// <Greeting/>
// </div>
// )
}
}
export default App;
运行程序提示出现错误
TypeError: Cannot add property myName, object is not extensible
这是因为这个对象 el 是被冻结,我们无法对其添加属性或进行修改。可以通过Object.isFrozen
方法可以坚持 el 是否被冻结。
const el = React.createElement('h1',null,"hello react")
// el.myName = 'zidea';
console.log(Object.isFrozen(el));
返回 true 表示对象已经被冻结,冻结对象对象我们无法再为其添加新的属性。
true
const Title = ({title}) => React.createElement('h1',null,title)
class App extends Component{
render(){
return React.createElement(Title,{title:"hello"})
}
}
export default App;
const Title = ({title}) => React.createElement('h1',null,title)
class App extends Component{
constructor(props){
super(props);
this.state = {title:'zidea'}
}
render(){
return React.createElement(Title,{title:this.state.title})
}
}
尝试修改 props 同样可以可能会发生错误。
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
class App extends Component{
constructor(props){
super(props);
this.state = {title:'zidea'}
}
render(){
return React.createElement('h1',null,this.state.title)
}
}
![](https://img.haomeiwen.com/i8207483/b026e97f1c1d05ce.png)
![](https://img.haomeiwen.com/i8207483/10966430d1e4ddf9.png)
![](https://img.haomeiwen.com/i8207483/a0f8f90f2d863640.png)
通过上面演示我们可以查看,当
Object.freeze()
, 我们无法通过 delete 来删除对象的属性,也无法修改冻结对象的属性值,而使用 seal 虽然无法删除属性,但却可以修改对象的属性。
// an immutable object with a single mutable value
function createRef() {
var refObject = {
current: null
};
{
Object.seal(refObject);
}
return refObject;
}
看看 refObject 源码,这里通过Object.seal(refObject)
,因此我们可以修改 current 属性指向我们要引用的 DOM。
class App extends Component{
constructor(props){
super(props);
this.titleRef = { current:{}};
this.state = {title:'zidea'}
}
componentDidMount(){
console.log(this.titleRef.current);
}
render(){
return React.createElement('h1',{ref:this.titleRef},this.state.title)
}
}
从上面代码我们不难看出 current 的属性是可以修改
var hasSymbol = typeof Symbol === 'function' && Symbol.for;
var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2;
var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace;
var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf;
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1;
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
Symbol 可以创建一个唯一的 key 值,这个值是唯一的、可以通过一个实例来了解 Symbol 使用方法。我们可以通过 Symbol 来实现类似 java 中的接口。
上面语句不难看出我们通过判断是否支持 Symbol,如果支持就使用 Symbol 来作为类型的唯一标识,否则直接通过序列数来表示。
![](https://img.haomeiwen.com/i8207483/68ddc5ad4e70024e.png)
定义 Tut 类,然后提供一个 print 方法,调用可使用 tut.print
![](https://img.haomeiwen.com/i8207483/fb1d5b134f8b82fb.png)
检查是否为 react 的元素。保护你的代码,其实并没有那么复杂。
$$typeof: REACT_ELEMENT_TYPE,
class App extends Component{
constructor(props){
super(props);
this.titleRef = React.createRef();
this.state = {title:'zidea'}
}
componentDidMount(){
console.log(this.titleRef.current);
}
changetTitle(){
this.setState({title:'tina'})
}
render(){
return React.createElement('div',null,[
React.createElement('h1',{key:1},this.state.title),
React.createElement('button',{key:2, onClick:()=> this.changetTitle()},'click')
]
)
}
}
通过打印this.updater
可以输出 this.updater 的方法,这里需要说一下更新 setState 方法是异步的,可以通过 enqueueSetState 方法可以更新 state 属性值。
changetTitle(){
console.log(this.updater);
}
![](https://img.haomeiwen.com/i8207483/53daec68d5b2ef91.png)
changetTitle(){
this.updater.enqueueSetState(this,{title:'new title'});
}
网友评论