From 9e42dfdeaf6aed7f9461b62b447502132e05dde5 Mon Sep 17 00:00:00 2001 From: aspire-t Date: Mon, 6 Apr 2020 23:18:41 +0800 Subject: [PATCH] apChildren --- src/index.js | 40 ++++----- src/react/ReactBaseClasses.js | 26 +++--- src/react/ReactChildren.js | 80 ++++++++++++++++-- src/react/ReactCurrentOwner.js | 6 +- src/react/ReactElement.js | 146 +++++++++++++++++++-------------- src/react/index.js | 22 ++--- src/shared/ReactSymbols.js | 2 +- 7 files changed, 201 insertions(+), 121 deletions(-) diff --git a/src/index.js b/src/index.js index 8243347..737a3a1 100644 --- a/src/index.js +++ b/src/index.js @@ -1,26 +1,20 @@ - -import React, { Component } from './react'; -import ReactDOM from 'react-dom'; +import React, { Component } from './react' +import ReactDOM from 'react-dom' class Child extends Component { render() { - console.log(this.props.children); + // console.log(this.props.children) const mappedChildren = React.Children.map( this.props.children, - (item, index) => ( - [
{item}
,
{item}
] - ) - ); - console.log(mappedChildren); - return ( -
- {mappedChildren} -
+ (item, index) => [ +
{item}
, +
{item}
, + ] ) + console.log(mappedChildren) + return
{mappedChildren}
} } class App extends Component { - - render() { /* [1, 2, 3].map(item =>
  • {item}
  • ); 1.map(item =>
  • {item}
  • ); @@ -31,16 +25,14 @@ class App extends Component {
    child1
    child2
    child3
    - { - [ -
    child4
    , -
    child5
    , -
    child6
    - ] - } + {[ +
    child4
    , +
    child5
    , +
    child6
    , + ]} ) } } -console.log('App.prototype.isReactComponent', App.prototype.isReactComponent); -ReactDOM.render(, document.getElementById('root')); \ No newline at end of file +console.log('App.prototype.isReactComponent', App.prototype.isReactComponent) +ReactDOM.render(, document.getElementById('root')) diff --git a/src/react/ReactBaseClasses.js b/src/react/ReactBaseClasses.js index ae81361..6e5ee05 100644 --- a/src/react/ReactBaseClasses.js +++ b/src/react/ReactBaseClasses.js @@ -1,17 +1,15 @@ - -let emptyObject = {}; +let emptyObject = {} class Component { - constructor(props, context) { - this.props = props; - this.context = context; - this.refs = emptyObject; - } + constructor(props, context) { + this.props = props + this.context = context + this.refs = emptyObject + } } - //在React内部是凭这个变量来判断是不是一个React组件的 - //因为组件定义的有两种方式,一种是类组件,一种函数组件,都被babel编译成函数 - Component.prototype.isReactComponent = { -}; +//在React内部是凭这个变量来判断是不是一个React组件的 +//因为组件定义的有两种方式,一种是类组件,一种函数组件,都被babel编译成函数 +Component.prototype.isReactComponent = {} -class PureComponent extends Component { } -PureComponent.prototype.isPureReactComponent = true; -export { Component } \ No newline at end of file +class PureComponent extends Component {} +PureComponent.prototype.isPureReactComponent = true +export { Component } diff --git a/src/react/ReactChildren.js b/src/react/ReactChildren.js index bbc07d8..48243f3 100644 --- a/src/react/ReactChildren.js +++ b/src/react/ReactChildren.js @@ -1,8 +1,78 @@ +import { cloneAndReplaceKey } from './ReactElement' + function mapChildren(children, func, context) { - //TODO实现此mapChildren方法 - return children; + // TODO实现此mapChildren方法 + if (children == null) { + return children + } + const result = [] + mapIntoArray(children, result, '', func) + return result +} + +let count = 0 +function mapIntoArray(children, array, escapedPrefix, callback) { + const type = typeof children + + if (type === 'undefined' || type === 'boolean') { + children = null + } + + for (let i = 0; i < children.length; i++) { + const element = children[i] + if (element.length > 0) { + mapIntoArray(element, array, i, callback) + } else { + let preKey = '' + if (element.key) { + preKey = element.key + } + let res = callback(element, count) + + let res2 = res.map((item) => { + let key = handleKey(item, count, preKey, escapedPrefix) + return cloneAndReplaceKey(item, key) + }) + + count++ + array.push(...res2) + } + } } -export { - mapChildren as map, -}; \ No newline at end of file +// 总的来说就是要评Key,我这个写法好像是只能满足一层数组,如果是多层数组,比如:[a,[a,[a,a]]],我这个方法应该就会出问题 +// 源码中好像是用正则去实现这个问题的,但是我还没看明白,还要再去研究研究…… +function handleKey(element, count, preKey, escapedPrefix) { + let key = '' + + if (preKey !== '') { + key += `.$${preKey}/` + } else { + key += `.${count}/` + } + + if (element.key) { + key = `${key}.$${element.key}` + } + + if (escapedPrefix !== '') { + key = `.${escapedPrefix}:${key}` + } + console.log(key) + return key +} + +export { mapChildren as map } + +// .0/.$div0A +// .0/.$div0B +// .$key2/.$div1A +// .$key2/.$div1B +// .$key3/.$div2A +// .$key3/.$div2B +// .3:$key4/.$div3A +// .3:$key4/.$div3B +// .3:$key5/.$div4A +// .3:$key5/.$div4B +// .3:$key6/.$div5A +// .3:$key6/.$div5B diff --git a/src/react/ReactCurrentOwner.js b/src/react/ReactCurrentOwner.js index 0bc1545..b120006 100644 --- a/src/react/ReactCurrentOwner.js +++ b/src/react/ReactCurrentOwner.js @@ -1,5 +1,5 @@ const ReactCurrentOwner = { - current: null -}; + current: null, +} -export default ReactCurrentOwner; \ No newline at end of file +export default ReactCurrentOwner diff --git a/src/react/ReactElement.js b/src/react/ReactElement.js index 25fdf5e..4dbe43e 100644 --- a/src/react/ReactElement.js +++ b/src/react/ReactElement.js @@ -1,74 +1,98 @@ +import ReactCurrentOwner from './ReactCurrentOwner' +import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols' -import ReactCurrentOwner from './ReactCurrentOwner'; -import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols'; function hasValidRef(config) { - return config.ref !== undefined; + return config.ref !== undefined } + function hasValidKey(config) { - return config.key !== undefined; + return config.key !== undefined } + const RESERVED_PROPS = { - key: true, - ref: true, - __self: true, - __source: true + key: true, + ref: true, + __self: true, + __source: true, } + export function createElement(type, config, children) { - let propName;//定义一个变量叫属性名 - const props = {};//定义一个元素的props对象 - let key = null;//在兄弟节点中唯一标识自己的唯一性的,在同一个的不同兄弟之间key要求不同 - let ref = null;//ref=React.createRef() "username" this.refs.username {input=>this.username = input} 从而得到真实的DOM元素 - let self = null;//用来获取真实的this指针 - let source = null;//用来定位创建此虚拟DOM元素在源码的位置 哪个文件 哪一行 哪一列 - if (config !== null) { - if (hasValidRef(config)) { - ref = config.ref; - } - if (hasValidKey(config)) { - key = config.key; - } - self = config.__self === undefined ? null : config.__self; - source = config.__source === undefined ? null : config.__source; - for (propName in config) { - if (!RESERVED_PROPS.hasOwnProperty(propName)) { - props[propName] = config[propName] - } - } + let propName //定义一个变量叫属性名 + const props = {} //定义一个元素的props对象 + let key = null //在兄弟节点中唯一标识自己的唯一性的,在同一个的不同兄弟之间key要求不同 + let ref = null //ref=React.createRef() "username" this.refs.username {input=>this.username = input} 从而得到真实的DOM元素 + let self = null //用来获取真实的this指针 + let source = null //用来定位创建此虚拟DOM元素在源码的位置 哪个文件 哪一行 哪一列 + if (config !== null) { + if (hasValidRef(config)) { + ref = config.ref } - const childrenLength = arguments.length - 2; - if (childrenLength === 1) { - props.children = children;//如果说是独生子的话children是一个对象 - } else if (childrenLength > 1) { - const childArray = Array(childrenLength); - for (let i = 0; i < childrenLength; i++) { - childArray[i] = arguments[i + 2]; - } - props.children = childArray;//如果说是有多个儿子的话,props.children就是一个数组了 + if (hasValidKey(config)) { + key = config.key } - if (type && type.defaultProps) { - const defaultProps = type.defaultProps; - //只有当属性对象没有此属性对应的值的时候,默认属性才会生效,否则直接忽略 - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName] - } - } + self = config.__self === undefined ? null : config.__self + source = config.__source === undefined ? null : config.__source + for (propName in config) { + if (!RESERVED_PROPS.hasOwnProperty(propName)) { + props[propName] = config[propName] + } } - //ReactCurrentOwner此元素的拥有者 - return ReactElement( - type, key, ref, self, source, ReactCurrentOwner.current, props - ) + } + const childrenLength = arguments.length - 2 + if (childrenLength === 1) { + props.children = children //如果说是独生子的话children是一个对象 + } else if (childrenLength > 1) { + const childArray = Array(childrenLength) + for (let i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2] + } + props.children = childArray //如果说是有多个儿子的话,props.children就是一个数组了 + } + if (type && type.defaultProps) { + const defaultProps = type.defaultProps + //只有当属性对象没有此属性对应的值的时候,默认属性才会生效,否则直接忽略 + for (propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName] + } + } + } + //ReactCurrentOwner此元素的拥有者 + return ReactElement( + type, + key, + ref, + self, + source, + ReactCurrentOwner.current, + props + ) } + function ReactElement(type, key, ref, _self, _source, _owner, props) { - const element = { - $$typeof: REACT_ELEMENT_TYPE, - type, - key, - ref, - props, - _owner, - _self, - _source - } - return element; -} \ No newline at end of file + const element = { + $$typeof: REACT_ELEMENT_TYPE, + type, + key, + ref, + props, + _owner, + _self, + _source, + } + return element +} + +export function cloneAndReplaceKey(oldElement, newKey) { + const newElement = ReactElement( + oldElement.type, + newKey, + oldElement.ref, + oldElement._self, + oldElement._source, + oldElement._owner, + oldElement.props + ) + + return newElement +} diff --git a/src/react/index.js b/src/react/index.js index 51cf135..fbaca87 100644 --- a/src/react/index.js +++ b/src/react/index.js @@ -1,15 +1,11 @@ - - -import { Component } from './ReactBaseClasses'; -import { createElement } from './ReactElement'; -import { map } from './ReactChildren'; +import { Component } from './ReactBaseClasses' +import { createElement } from './ReactElement' +import { map } from './ReactChildren' const React = { - createElement, - Children: { - map - }, + createElement, + Children: { + map, + }, } -export { - Component -} -export default React; \ No newline at end of file +export { Component } +export default React diff --git a/src/shared/ReactSymbols.js b/src/shared/ReactSymbols.js index bad4224..80bf07f 100644 --- a/src/shared/ReactSymbols.js +++ b/src/shared/ReactSymbols.js @@ -1 +1 @@ -export const REACT_ELEMENT_TYPE = Symbol.for('react.element') \ No newline at end of file +export const REACT_ELEMENT_TYPE = Symbol.for('react.element') -- Gitee