import { shouldSetTextContent } from './ReactFiberHostConfig' ; import { cloneChildFibers , mountChildFibers , reconcileChildFibers , } from './ReactChildFiber' ; import { bailoutHooks , renderWithHooks } from './ReactFiberHooks' ; import { Fiber } from './ReactInternalTypes' ; import { cloneUpdateQueue , processUpdateQueue } from './ReactUpdateQueue' ; import { FunctionComponent , HostComponent , HostRoot , HostText , IndeterminateComponent , MemoComponent , SimpleMemoComponent , } from './ReactWorkTags' ; import { includesSomeLane , Lanes , NoLanes } from './ReactFiberLane' ; import { ContentReset } from './ReactFiberFlags' ; import { createFiberFromTypeAndProps , createWorkInProgress , isSimpleFunctionComponent , } from './ReactFiber' ; import { shallowEqual } from '../shared/shallowEqual' ; let didReceiveUpdate = false ; const updateFunctionComponent = ( current , workInProgress , Component , nextProps , renderLanes ) : Fiber | null => { const nextChildren = renderWithHooks ( current , workInProgress , Component as any , nextProps , null , renderLanes ) ; if ( current !== null && ! didReceiveUpdate ) { bailoutHooks ( current , workInProgress , renderLanes ) ; return bailoutOnAlreadyFinishedWork ( current , workInProgress , renderLanes ) ; } reconcileChildren ( current , workInProgress , nextChildren , renderLanes ) ; return workInProgress . child ; } ; param current param workInProgress param renderLanes returns const bailoutOnAlreadyFinishedWork = ( current , workInProgress , renderLanes ) : Fiber | null => { if ( ! includesSomeLane ( renderLanes , workInProgress . childLanes ) ) { /**
         * children也没有待进行的工作，我们可以直接跳过他们的render工作
         */ return null ; } cloneChildFibers ( current , workInProgress ) ; return workInProgress . child ; } ; param current param workInProgress returns const updateHostRoot = ( current , workInProgress , renderLanes ) => { cloneUpdateQueue ( current , workInProgress ) ; const prevState = workInProgress . memoizedState ; const prevChildren = prevState !== null ? prevState . element : null ; const nextProps = workInProgress . pendingProps ; processUpdateQueue ( workInProgress , nextProps , null ) ; const nextState = workInProgress . memoizedState ; const nextChildren = nextState . element ; if ( nextChildren === prevChildren ) { return null ; } reconcileChildren ( current , workInProgress , nextChildren , renderLanes ) ; return workInProgress . child ; } ; const reconcileChildren = ( current , workInProgress , nextChildren , renderLanes ) => { if ( current === null ) { workInProgress . child = mountChildFibers ( workInProgress , null , nextChildren , renderLanes ) ; } else { workInProgress . child = reconcileChildFibers ( workInProgress , current . child , nextChildren , renderLanes ) ; } } ; param current param workInProgress param Component param renderLanes returns const mountIndeterminateComponent = ( current , workInProgress , Component , renderLanes ) : Fiber | null => { const props = workInProgress . pendingProps ; const value = renderWithHooks ( current , workInProgress , Component , props , null , renderLanes ) ; workInProgress . tag = FunctionComponent ; reconcileChildren ( null , workInProgress , value , renderLanes ) ; return workInProgress . child ; } ; const updateHostComponent = ( current , workInProgress , renderLanes ) => { const type = workInProgress . type ; const nextProps = workInProgress . pendingProps ; const prevProps = current !== null ? current . memoizedProps : null ; let nextChildren = nextProps . children ; const isDirectTextChild = shouldSetTextContent ( type , nextProps ) ; if ( isDirectTextChild ) { /**
         * 我们把子节点为文本这种情况特别处理，这是一种非常常见的情况
         * 在这不会为该文本创建实际的fiber节点而是只把他放到props.children
         * 待会更新props时会直接setTextContent把他设置到dom上，以避免还要创建
         * 一个fiber节点，并遍历他
         * 注意只有<div>sdfsd dsfsd</div>，或者 <div>{1}</div>这种才算时
         * 直接文本子节点<div>{1}{2}</div>这种children类型是数组其中1，和2都会
         * 创建一个fiber节点与之对应，更多例子可以上[https://babeljs.io/repl/]
         * 自行把玩
         */ nextChildren = null ; } else if ( prevProps !== null && shouldSetTextContent ( type , prevProps ) ) { /**
         * 此次更新时，当前需要被替换的节点一个单纯的文本节点，他没有对应的fiber节点
         * 所以不能靠reconcile过程把他删除，所以我们在这直接把他的父节点打上ContentReset
         * 标签待会commit阶段的时候它会被`textContent = ''`删除，这样他就能正常的被新内容替换，否则他将不会被清除一直存在在
         * 他的父节点上
         */ workInProgress . flags |= ContentReset ; } reconcileChildren ( current , workInProgress , nextChildren , renderLanes ) ; return workInProgress . child ; } ; const updateSimpleMemoComponent = ( current , workInProgress , Component , nextProps , updateLanes , renderLanes ) : null | Fiber => { if ( current !== null ) { const prevProps = current . memoizedProps ; if ( shallowEqual ( prevProps , nextProps ) ) { didReceiveUpdate = false ; if ( ! includesSomeLane ( renderLanes , updateLanes ) ) { /**
                 * 考虑以下代码
                 * let hasDispatched = false
                 * const Foo = memo(() => {
                 *   const [list, setList] = useState<number[]>([])
                 *
                 *   setTimeout(() => {
                 *     if (hasDispatched) return
                 *
                 *     hasDispatched = true
                 *     setList(Array.from({ length: 1e4 }, (_, i) => i))
                 *   }, 1000)
                 *
                 *   return (
                 *     <div>
                 *       {list.map((v) => (
                 *         <div>{v}</div>
                 *       ))}
                 *     </div>
                 *   )
                 * })
                 *
                 * const App = () => {
                 *   const [count, setCount] = useState(0)
                 *
                 *   useEffect(() => {
                 *     setTimeout(() => {
                 *       const dispatcher = document.getElementById('dispatcher')
                 *       dispatcher?.click()
                 *     }, 1030)
                 *   }, [])
                 *   return (
                 *     <div>
                 *       <button
                 *         id="dispatcher"
                 *         onClick={() => {
                 *           setCount(1)
                 *         }}
                 *       >
                 *         {count}
                 *       </button>
                 *       <Foo />
                 *     </div>
                 *   )
                 * }
                 * 当进行Foo组件的渲染时，它会被App组件内产生的更高的优先级的更新打断，
                 * 所以会先开始以renderLanes为1开始一轮更新，而此时Foo组件的UpdateLanes为
                 * 16,如果没有memo组件的情况下他不会提前bailout,而会继续render过程
                 * 在执行updateReducer时处理他updateQueue上因优先级不足而被跳过的update而被打上相应的lanes
                 * 而现在他被包在memo里面所以他会进入这里的逻辑，
                 * 而我们在这里提前进行bailout就得手动设置他workInProgress上的lanes
                 * 如果我们运行上面的代码，并且没有下面这行的代码的话，Foo组件内产生的更新就会好像消失了一样
                 */ workInProgress . lanes = current . lanes ; return bailoutOnAlreadyFinishedWork ( current , workInProgress , renderLanes ) ; } } } return updateFunctionComponent ( current , workInProgress , Component , nextProps , renderLanes ) ; } ; const updateMemoComponent = ( current , workInProgress , Component , nextProps , updateLanes , renderLanes ) : null | Fiber => { if ( current === null ) { const type = Component . type ; if ( isSimpleFunctionComponent ( type ) && Component . compare === null && Component . defaultProps === undefined ) { let resolvedType = type ; workInProgress . tag = SimpleMemoComponent ; workInProgress . type = resolvedType ; return updateSimpleMemoComponent ( current , workInProgress , resolvedType , nextProps , updateLanes , renderLanes ) ; } const child = createFiberFromTypeAndProps ( Component . type , null , nextProps , workInProgress . mode , renderLanes ) ; child . return = workInProgress ; workInProgress . child = child ; return child ; } const currentChild = current . child as Fiber ; if ( ! includesSomeLane ( updateLanes , renderLanes ) ) { const prevProps = currentChild . memoizedProps ; let compare = Component . compare ; compare = compare !== null ? compare : shallowEqual ; if ( compare ( prevProps , nextProps ) ) { return bailoutOnAlreadyFinishedWork ( current , workInProgress , renderLanes ) ; } } const newChild = createWorkInProgress ( currentChild , nextProps ) ; newChild . return = workInProgress ; workInProgress . child = newChild ; return newChild ; } ; param current param workInProgress returns export const beginWork = ( current , workInProgress , renderLanes ) : Fiber | null => { const updateLanes = workInProgress . lanes ; if ( current !== null ) { const oldProps = current . memoizedProps ; const newProps = workInProgress . pendingProps ; if ( oldProps !== newProps ) { didReceiveUpdate = true ; } else if ( ! includesSomeLane ( renderLanes , updateLanes ) ) { didReceiveUpdate = false ; switch ( workInProgress . tag ) { case HostRoot : break ; case HostComponent : break ; case HostText : break ; case FunctionComponent : break ; case SimpleMemoComponent : break ; default : { throw new Error ( 'Not Implement' ) ; } } return bailoutOnAlreadyFinishedWork ( current , workInProgress , renderLanes ) ; } } else { didReceiveUpdate = false ; } workInProgress . lanes = NoLanes ; switch ( workInProgress . tag ) { case IndeterminateComponent : { return mountIndeterminateComponent ( current , workInProgress , workInProgress . type , renderLanes ) ; } case FunctionComponent : { const Component = workInProgress . type ; const unresolvedProps = workInProgress . pendingProps ; const resolvedProps = unresolvedProps ; return updateFunctionComponent ( current ! , workInProgress , Component , resolvedProps , renderLanes ) ; } case HostRoot : { return updateHostRoot ( current ! , workInProgress , renderLanes ) ; } case HostComponent : return updateHostComponent ( current , workInProgress , renderLanes ) ; case HostText : return null ; case MemoComponent : { const type = workInProgress . type ; const unresolvedProps = workInProgress . pendingProps ; return updateMemoComponent ( current , workInProgress , type , unresolvedProps , updateLanes , renderLanes ) ; } case SimpleMemoComponent : { return updateSimpleMemoComponent ( current , workInProgress , workInProgress . type , workInProgress . pendingProps , updateLanes , renderLanes ) ; } } throw new Error ( 'Not Implement' ) ; } ; export const markWorkInProgressReceivedUpdate = ( ) => { didReceiveUpdate = true ; } ;