1.portal组件更新
1.api返回的$$type为portal 这个和reactElement处于同等级
ReactDOM.createPortal直接返回的一个对象结构就有children
return {
// This tag allow us to uniquely identify this as a React Portal
$$typeof: REACT_PORTAL_TYPE,
key: key == null ? null : '' + key,
children,
containerInfo,
implementation,
};
复制代码
在最开始的创建fiber树阶段 这个节点就是个fiber 不过tag=5 children就是传进来的children 和之前一样 只是在commit阶段会把这个节点挂载到别的地方去
{this.state.show ? (
<p class='ta'>{ReactDOM.createPortal(<span>123</span>, portalElm)}</p>
) : null}
复制代码
p标签的props如下
证明ReactDOM.createPortal函数返回啦一个这一的普通对象 concilechildren时候这个对象成啦一个fiber
{
// This tag allow us to uniquely identify this as a React Portal
$$typeof: REACT_PORTAL_TYPE,
key: key == null ? null : '' + key,
children,
containerInfo,
implementation,
};
复制代码
下一次performunitofwork时候就是这个fiber tag是4一直下去建立fiber树
但是最终的移动元素是在commit阶段
2.forwardRef更新
形成的react内部组件的type是如下对象
return {
$$typeof: REACT_FORWARD_REF_TYPE, //!给一个特定的ref_type
render,//! render就是传进来的函数组件
};
复制代码
父元素的fiber的属性整体还是 只有protal是typeof: react_element,然后靠type的$$type去区分
{
pendingprops:{
children:{
$$typeof: react_element,
type:{
$$typeof: REACT_FORWARD_REF_TYPE,
render
}
}
}
}
复制代码
更新 forwardRef的创建fiber的第一次的children是来自render的调用返回的children 和函数组件一样
function updateForwardRef(
current: Fiber | null,
workInProgress: Fiber,
type: any,
nextProps: any,
renderExpirationTime: ExpirationTime,
) {
const render = type.render;
const ref = workInProgress.ref;//!拿到传到forward组件上的进来的ref 自动调用react.createElement 但是ref不会和prop合并 所以直接在fiber上
if (hasLegacyContextChanged()) {//!context相关
// Normally we can bail out on props equality but if context has changed
// we don't do the bailout and we have to reuse existing props instead.
} else if (workInProgress.memoizedProps === nextProps) {
const currentRef = current !== null ? current.ref : null;
if (ref === currentRef) {//!ref没变直接不更新 ForwardRef更新只能是ref改变
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderExpirationTime,
);
}
}
//!props发生改变 函数组件的children需要reconcile
let nextChildren;
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
ReactCurrentFiber.setCurrentPhase('render');
nextChildren = render(nextProps, ref);//!拿到ref之后作为参数传给啦函数组件 此时这个函数组件就是个普通函数 不会有单独的fiber 其返回值直接作为forwrardref的children
ReactCurrentFiber.setCurrentPhase(null);
} else {
nextChildren = render(nextProps, ref);
}
reconcileChildren(
current,
workInProgress,
nextChildren,
renderExpirationTime,
);
return workInProgress.child;
}
复制代码
3.mode组件更新
调和到这个mode组件时候,mode组件的fiber对象上有个mode属性为你这个mode 比如是concurrentMODE 是二进制形式 调和孩子组件时候所有孩子fiber也会继续使用这个父组件的mode值 以此记录这个子树是在那个mode下,子组件的创建更新的expirationtime会有一个特殊的计算过程
4.memo组件更新
api
export default function memo<Props>(
type: React$ElementType,
compare?: (oldProps: Props, newProps: Props) => boolean,
) {
if (__DEV__) {
if (!isValidElementType(type)) {
warningWithoutStack(
false,
'memo: The first argument must be a component. Instead ' +
'received: %s',
type === null ? 'null' : typeof type,
);
}
}
return {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
}
复制代码
返回对象为 作为type
{
$$typeof: REACT_MEMO_TYPE,
type,//!这个type是我们传进来的functionComponent的type
compare: compare === undefined ? null : compare,
};
复制代码
源码:
function updateMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,//!就是传到memo上的props 因为react.createElement会自动设置props
updateExpirationTime,
renderExpirationTime: ExpirationTime,
): null | Fiber {
if (current === null) {//!current === null 主要是辨别是否是第一次渲染
let type = Component.type;//!第一次渲染
// !Component是对象{
// $$typeof: REACT_MEMO_TYPE,
// type,//!这个type是我们传进来的函数组件
// compare: compare === undefined ? null : compare,
// };
//!那么获取的type就是函数组件(调用memo传进来的第一个参数)的type
if (isSimpleFunctionComponent(type) && Component.compare === null) {//!看看我们传进来的第二个参数 即什么条件不刷新组件 如果没传入
//!isSimpleFunctionComponent 表示是个纯函数组件不是类组件
// If this is a plain function component without default props,
// and with only the default shallow comparison, we upgrade it
// to a SimpleMemoComponent to allow fast path updates.
workInProgress.tag = SimpleMemoComponent;
workInProgress.type = type;
return updateSimpleMemoComponent(//!采用简单的判断条件来刷新组件
current,
workInProgress,
type,//!函数组件
nextProps,
updateExpirationTime,
renderExpirationTime,
);
}
//!还是第一次创建 这里直接创建子函数组件的fiber作为memo的孩子(注意不是函数组件的children的fiber作为子child)
let child = createFiberFromTypeAndProps(
Component.type,
null,
nextProps,
null,
workInProgress.mode,
renderExpirationTime,
);
child.ref = workInProgress.ref;
child.return = workInProgress;
workInProgress.child = child;
return child;
}
//!不是第一次渲染 currentChild为上次的子函数fiber
let currentChild = ((current.child: any): Fiber); // This is always exactly one child
if (
updateExpirationTime === NoWork ||
updateExpirationTime > renderExpirationTime//!不需要更新
) {
// This will be the props with resolved defaultProps,
// unlike current.memoizedProps which will be the unresolved ones.
const prevProps = currentChild.memoizedProps;
// Default to shallow comparison
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
//!判断函数组件的props和这次传给memo的props是否发生变化
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {//!传入啦compare 返回true则不需要更新
return bailoutOnAlreadyFinishedWork(//!直接跳过
current,
workInProgress,
renderExpirationTime,
);
}
}
//!需要更新 创建新的函数组件的fiber当作child
let newChild = createWorkInProgress(
currentChild,//!函数组件
nextProps,//!新的props
renderExpirationTime,
);
newChild.ref = workInProgress.ref;
newChild.return = workInProgress;
workInProgress.child = newChild;
return newChild;
}
function updateSimpleMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
updateExpirationTime,
renderExpirationTime: ExpirationTime,
): null | Fiber {
if (
current !== null &&
(updateExpirationTime === NoWork ||
updateExpirationTime > renderExpirationTime)//!当前组件需要更新
) {
const prevProps = current.memoizedProps;
if (
shallowEqual(prevProps, nextProps) &&//!浅比较props
current.ref === workInProgress.ref
) {
//!不更新
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderExpirationTime,
);
}
}
//!把这个组件当作函数组件更新 Component就是那个函数 children通过调用这个函数获取
return updateFunctionComponent(
current,
workInProgress,
Component,
nextProps,
renderExpirationTime,
);
}
复制代码
1.非简单更新
memo创建就是直接创建内部的函数组件fiber作为child(传给他传给他props) 只是多加啦一层判断是否要更新
memo更新就是走createWorkInProgress 复用之前的fiber改变下props 到那个函数组件调和时候再去recocile他的children
2.简单更新即updateSimpleMemoComponent
这个时候memo的child就是函数组件的children的第一个组件fiber 函数组件fiber就没了 以后更新也是对这个fiber进行更新 这个时候后面走的都是
updateSimpleMemoComponent这个方法(直接去更新函数组件即子组件) 而不是去走createWorkInProgress这个方法