react
今天我们来分析一下 React 的源码, 以及在 React 中应用了那些 ES6 的新特性.
首先感谢 Nir Kaufman 大神的分享, 最近看了他分享 Redux Pattern 受益匪浅.
nir kaufman
下面代码想必大家不会陌生, 我们通过 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)
- }
- }
freeze
change name
seal
通过上面演示我们可以查看, 当 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 来作为类型的唯一标识, 否则直接通过序列数来表示.
图 1
定义 Tut 类, 然后提供一个 print 方法, 调用可使用 tut.print
图 2
检查是否为 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);
- }
updater
- changetTitle(){
- this.updater.enqueueSetState(this,{title:'new title'});
- }
来源: http://www.jianshu.com/p/a12db80bdad1