import { DefaultEventPriority } from '../react-reconciler/ReactEventPriorities' ; import { Lane } from '../react-reconciler/ReactFiberLane' ; import { Fiber } from '../react-reconciler/ReactInternalTypes' ; import { registrationNameDependencies } from './events/EventRegistry' ; import { precacheFiberNode , updateFiberProps , } from './events/ReactDOMComponentTree' ; import { getEventPriority } from './events/ReactDOMEventListener' ; import { setInitialProperties , updateProperties } from './ReactDOMComponent' ; import { Container } from './ReactDomRoot' ; import { getHostProps as ReactDOMInputGetHostProps } from './ReactDOMInput' ; import { setTextContent } from './setTextContent' ; const STYLE = 'style' ; const CHILDREN = 'children' ; export type Props = { autoFocus ? : boolean ; children ? : unknown ; disabled ? : boolean ; hidden ? : boolean ; suppressHydrationWarning ? : boolean ; dangerouslySetInnerHTML ? : unknown ; style ? : object & { display ? : string ; } ; bottom ? : null | number ; left ? : null | number ; right ? : null | number ; top ? : null | number ; } ; export type UpdatePayload = unknown [ ] ; export type Type = string ; param type param props returns export const shouldSetTextContent = ( type , props ) : boolean => { return ( type === 'textarea' || type === 'option' || type === 'noscript' || typeof props . children === 'string' || typeof props . children === 'number' || ( typeof props . dangerouslySetInnerHTML === 'object' && props . dangerouslySetInnerHTML !== null && ( props . dangerouslySetInnerHTML as any ) . __html !== null ) ) ; } ; export const createInstance = ( type , props , internalInstanceHandle ) => { const domElement = document . createElement ( type ) ; precacheFiberNode ( internalInstanceHandle , domElement ) ; updateFiberProps ( domElement , props ) ; return domElement ; } ; export const appendInitialChild = ( parentInstance , child ) => { parentInstance . appendChild ( child ) ; } ; export const insertBefore = ( parentInstance , child , beforeChild ) : void => { parentInstance . insertBefore ( child , beforeChild ) ; } ; export const appendChild = ( parentInstance , child ) : void => { parentInstance . appendChild ( child ) ; } ; const COMMENT_NODE = 8 ; param container param child param beforeChild export const insertInContainerBefore = ( container , child , beforeChild ) => { if ( container . nodeType === COMMENT_NODE ) { container . parentNode ?. insertBefore ( child , beforeChild ) ; } else { container . insertBefore ( child , beforeChild ) ; } } ; export const appendChildToContainer = ( container , child ) : void => { let parentNode ; if ( container . nodeType === COMMENT_NODE ) { parentNode = container . parentNode ; parentNode ?. insertBefore ( child , container ) ; } else { parentNode = container ; parentNode . appendChild ( child ) ; } } ; param domElement param type param props returns export const finalizeInitialChildren = ( domElement , type , props ) : boolean => { setInitialProperties ( domElement , type , props ) ; return false ; } ; export const createTextInstance = ( text ) : Text => { const instance = document . createTextNode ( text ) ; return instance ; } ; export const scheduleMicrotask = queueMicrotask ; const diffProperties = ( domElement , tag , lastRawProps , nextRawProps ) : null | Array < unknown > => { let updatePayload = [ ] ; let lastProps ; let nextProps ; switch ( tag ) { case 'input' : lastProps = ReactDOMInputGetHostProps ( domElement , lastRawProps ) ; nextProps = ReactDOMInputGetHostProps ( domElement , nextRawProps ) ; updatePayload = [ ] ; break ; case 'option' : case 'select' : case 'textarea' : throw new Error ( 'Not Implement' ) ; default : { lastProps = lastRawProps ; nextProps = nextRawProps ; } } let propKey ; let styleName ; let styleUpdates = null ; for ( propKey in lastProps ) { if ( nextProps . hasOwnProperty ( propKey ) || ( ! lastProps . hasOwnProperty ( propKey ) && lastProps [ propKey ] == null ) ) { continue ; } const nextProp = nextProps [ propKey ] ; if ( propKey === STYLE ) { throw new Error ( 'Not Implement' ) ; } else if ( propKey === CHILDREN ) { } else { ; ( updatePayload = updatePayload || [ ] ) . push ( propKey , null ) ; } } for ( propKey in nextProps ) { const nextProp = nextProps [ propKey ] ; const lastProp = lastProps !== null ? lastProps [ propKey ] : undefined ; if ( ! nextProps . hasOwnProperty ( propKey ) || nextProp === lastProp || ( nextProp === null && lastProp === null ) ) { continue ; } if ( propKey === STYLE ) { if ( lastProp ) { for ( styleName in lastProp ) { if ( lastProp . hasOwnProperty ( styleName ) && ( ! nextProp || ! nextProp . hasOwnProperty ( styleName ) ) ) { if ( ! styleUpdates ) { styleUpdates = { } ; } styleUpdates [ styleName ] = '' ; } } for ( styleName in nextProp ) { if ( nextProp . hasOwnProperty ( styleName ) && lastProp [ styleName ] !== nextProp [ styleName ] ) { if ( ! styleUpdates ) { styleUpdates = { } ; } styleUpdates [ styleName ] = nextProp [ styleName ] ; } } } else { if ( ! styleUpdates ) { if ( ! updatePayload ) { updatePayload = [ ] ; } updatePayload . push ( propKey , styleUpdates ) ; } styleUpdates = nextProp ; } } else if ( registrationNameDependencies . hasOwnProperty ( propKey ) ) { if ( ! updatePayload ) updatePayload = [ ] ; } else if ( propKey === CHILDREN ) { if ( typeof nextProp === 'string' || typeof nextProp === 'number' ) { ; ( updatePayload = updatePayload || [ ] ) . push ( propKey , '' + nextProp ) ; } } else { ; ( updatePayload = updatePayload || [ ] ) . push ( propKey , nextProp ) ; } } if ( styleUpdates ) { ; ( updatePayload = updatePayload || [ ] ) . push ( STYLE , styleUpdates ) ; } return updatePayload ; } ; param domElement param type param oldProps param newProps returns export const prepareUpdate = ( domElement , type , oldProps , newProps ) : null | unknown [ ] => { return diffProperties ( domElement , type , oldProps , newProps ) ; } ; export const commitTextUpdate = ( textInstance , oldText , newText ) : void => { textInstance . nodeValue = newText ; } ; export const commitUpdate = ( domElement , updatePayload , type , oldProps , newProps , internalInstanceHandle ) : void => { /**
     * 更新fiber属性，ReactDOM事件系统能正常工作的关键
     * 比如如下代码
     * const Foo = () => {
     *   const [count, setCount] = useState(0)
     *
     *   return <div onClick={() => {
     *              setCount(count + 1)
     *           }}>{count}</div>
     * }
     * 如果不更新props的话，ReactDOM中事件机制执行时
     * 从dom对应fiber提取到的onClick事件的handler将永远是首次mount时
     * 的handler，这意味着他闭包中捕获到的count值永远都是0,所以不管你点击多少次div
     * 他都等价于setCount(0 + 1),所以会导致不能正常更新
     * 而调用了下面的updateFiberProps就不一样了，每次更新后handler里面闭包捕获到的count
     * 都是最新值所以能正常更新
     */ updateFiberProps ( domElement , newProps ) ; updateProperties ( domElement , updatePayload , type , oldProps , newProps ) ; } ; returns export const getCurrentEventPriority = ( ) : Lane => { const currentEvent = window . event ; if ( currentEvent === undefined ) { return DefaultEventPriority ; } return getEventPriority ( currentEvent . type as any ) ; } ; export const removeChild = ( parentInstance , child ) => { parentInstance . removeChild ( child ) ; } ; export const resetTextContent = ( domElement ) : void => { setTextContent ( domElement , '' ) ; } ;