npm i lerna -g
mkdir lerna-project
cd lerna-project
lerna init
lerna notice cli v4.0.0
lerna info Initializing Git repository
lerna info Creating package.json
lerna info Creating lerna.json
lerna info Creating packages directory
lerna success Initialized Lerna files
package.json
{
"name": "root",
"private": true, // 私有的,用来管理整个项目,不会被发布到npm
"devDependencies": {
"lerna": "^4.0.0"
}
}
lerna.json
{
"packages": [
"packages/*"
],
"version": "0.0.0"
}
yarn workspace
允许我们使用 monorepo
的形式来管理项目yarn.lock
文件。子项目也会被 link
到 node_modules
里面,这样就允许我们就可以直接用 import 导入对应的项目yarn.lock
文件是自动生成的,也完全Yarn来处理.yarn.lock
锁定你安装的每个依赖项的版本,这可以确保你不会意外获得不良依赖package.json
{
"name": "root",
"private": true,
+ "workspaces": [
+ "packages/*"
+ ],
"devDependencies": {
"lerna": "^3.22.1"
}
}
React.createElement
等代码lerna create react
lerna create shared
lerna create scheduler
lerna create react-reconciler
lerna create react-dom
yarn config get registry
yarn config set registry http://registry.npm.taobao.org/
yarn config set registry http://registry.npmjs.org/
yarn add chalk --ignore-workspace-root-check
yarn workspace react add object-assign
yarn install
lerna bootstrap --npm-client yarn --use-workspaces
作用 | 命令 |
---|---|
查看工作空间信息 | yarn workspaces info |
删除所有的 node_modules | lerna clean 等于 yarn workspaces run clean |
重新获取所有的 node_modules | yarn install --force |
查看缓存目录 | yarn cache dir |
清除本地缓存 | yarn cache clean |
git clone https://gitee.com/mirrors/react.git
cd react
yarn build react,shared,scheduler,react-reconciler,react-dom --type=NODE
cd build/node_modules/react
yarn link
cd build/node_modules/react-dom
yarn link
create-react-app debug-react17
cd debug-react17
yarn link react react-dom
import * as React from 'react';
import * as ReactDOM from 'react-dom';
class Counter extends React.Component{
state = {number:0}
buttonClick = ()=>{
console.log('buttonClick');
this.setState({number:this.state.number+1});
console.log(this.state.number);
this.setState({number:this.state.number+1});
console.log(this.state.number);
}
divClick = ()=>{
console.log('divClick');
}
render(){
return (
<div onClick={this.divClick} id="counter">
<p>{this.state.number}</p>
<button onClick={this.buttonClick}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
class Counter extends React.Component{
state = {number:0}
buttonClick = ()=>{
console.log('buttonClick');
+ this.setState({number:this.state.number+1},()=>{
+ console.log(this.state.number);
+ });
+ this.setState({number:this.state.number+1},()=>{
+ console.log(this.state.number);
+ });
}
divClick = ()=>{
console.log('divClick');
}
render(){
return (
<div onClick={this.divClick} id="counter">
<p>{this.state.number}</p>
<button onClick={this.buttonClick}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
class Counter extends React.Component{
state = {number:0}
buttonClick = ()=>{
console.log('buttonClick');
+ this.setState((state)=>({number:state.number+1}),()=>{
+ console.log(this.state.number);
+ });
+
+ this.setState((state)=>({number:state.number+1}),()=>{
+ console.log(this.state.number);
+ });
}
divClick = ()=>{
console.log('divClick');
}
render(){
return (
<div onClick={this.divClick} id="counter">
<p>{this.state.number}</p>
<button onClick={this.buttonClick}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'));
isBatchingUpdates
addEventListener
、setTimeout和setInterval
里无法设置import * as React from 'react';
import * as ReactDOM from 'react-dom';
class Counter extends React.Component{
state = {number:0}
buttonClick = ()=>{
console.log('buttonClick');// 2234
this.setState((state)=>({number:state.number+1}),()=>{
console.log(this.state.number);
});
this.setState((state)=>({number:state.number+1}),()=>{
console.log(this.state.number);
});
+ setTimeout(()=>{
+ this.setState((state)=>({number:state.number+1}),()=>{
+ console.log(this.state.number);
+ });
+
+ this.setState((state)=>({number:state.number+1}),()=>{
+ console.log(this.state.number);
+ });
});
}
divClick = ()=>{
console.log('divClick');
}
render(){
return (
<div onClick={this.divClick} id="counter">
<p>{this.state.number}</p>
<button onClick={this.buttonClick}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
class Counter extends React.Component{
state = {number:0}
buttonClick = ()=>{
console.log('buttonClick');// 2234
setTimeout(()=>{
+ ReactDOM.unstable_batchedUpdates(()=>{
+ this.setState((state)=>({number:state.number+1}));
+ console.log(this.state.number);
+ });
});
}
divClick = ()=>{
console.log('divClick');
}
render(){
return (
<div onClick={this.divClick} id="counter">
<p>{this.state.number}</p>
<button onClick={this.buttonClick}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'));
concurrent
模式+ReactDOM.unstable_createRoot(document.getElementById('root')).render(<Counter/>);
+ReactDOM.createRoot(document.getElementById('root')).render(<Counter/>);
import { HostRoot, ClassComponent } from './ReactWorkTags';
import { Component } from './ReactFiberClassComponent';
import { NoMode, ConcurrentMode } from './ReactTypeOfMode';
import { batchedUpdates } from './ReactFiberWorkLoop';
class Counter extends Component {
constructor() {
super();
this.state = { number: 0 };
}
onClick = (event) => {
this.setState({ number: this.state.number + 1 });
console.log('setState1', this.state.number);
this.setState({ number: this.state.number + 1 });
console.log('setState2', this.state.number);
setTimeout(() => {
this.setState({ number: this.state.number + 1 });
console.log('setTimeout setState1', this.state.number);
this.setState({ number: this.state.number + 1 });
console.log('setTimeout setState2', this.state.number);
});
}
render() {
console.log('render', this.state.number);
return this.state.number;
}
}
let counterInstance = new Counter();
let mode = ConcurrentMode;
let rootFiber = { tag: HostRoot, updateQueue: [], mode }
let counterFiber = { tag: ClassComponent, updateQueue: [], mode }
counterFiber.stateNode = counterInstance;
counterInstance._reactInternals = counterFiber;
counterFiber.return = rootFiber;
rootFiber.child = counterFiber;
//合成事件
document.addEventListener('click',(nativeEvent)=>{
let syntheticEvent = {nativeEvent};
batchedUpdates(()=>counterInstance.onClick(syntheticEvent));
});
//1.同步不批量
//counterInstance.onClick();
//2.同步批量
//batchedUpdates(counterInstance.onClick);
//3.异步批量
//counterInstance.onClick();
src\ReactWorkTags.js
export const HostRoot = 3;
export const ClassComponent = 1;
src\ReactTypeOfMode.js
export const NoMode = 0b00000;
export const ConcurrentMode = 0b00100;
src\ReactFiberClassComponent.js
import {scheduleUpdateOnFiber} from './ReactFiberWorkLoop';
let classComponentUpdater = {
enqueueSetState: function (inst, payload) {
const fiber = get(inst);
const update = createUpdate();
update.payload = payload;
enqueueUpdate(fiber, update);
scheduleUpdateOnFiber(fiber);
}
}
function get(inst){
return inst._reactInternals;
}
function createUpdate(){
return {};
}
function enqueueUpdate(fiber, update) {
var updateQueue = fiber.updateQueue;
updateQueue.push(update);
}
export class Component {
constructor() {
this.updater = classComponentUpdater;
}
setState(partialState) {
this.updater.enqueueSetState(this, partialState);
}
}
src\ReactFiberWorkLoop.js
import { ClassComponent, HostRoot } from './ReactWorkTags';
import {NoMode,ConcurrentMode} from './ReactTypeOfMode'
let syncQueue;
let NoLanePriority = 0;
let SyncLanePriority = 12;
export let NoContext = 0;
export let BatchedContext = 1;
export let executionContext = NoContext;
function markUpdateLaneFromFiberToRoot(fiber) {
let parent = fiber.return;
while (parent) {
fiber = parent;
parent = parent.return;
}
if (fiber.tag === HostRoot) {
return fiber;
}
return null;
}
export function getExecutionContext() {
return executionContext;
}
export function batchedUpdates(fn) {
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
try {
return fn();
} finally {
executionContext = prevExecutionContext;
if (executionContext === NoContext) {
flushSyncCallbackQueue();
}
}
}
export function scheduleUpdateOnFiber(fiber) {
let root = markUpdateLaneFromFiberToRoot(fiber);
ensureRootIsScheduled(root);
if (executionContext === NoContext && (fiber.mode & ConcurrentMode) === NoMode) {
flushSyncCallbackQueue();
}
}
function ensureRootIsScheduled(root) {
let existingCallbackPriority = root.callbackPriority;
let newCallbackPriority = SyncLanePriority;
if (existingCallbackPriority === newCallbackPriority) {
return;
}
scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
queueMicrotask(flushSyncCallbackQueue);
root.callbackPriority = newCallbackPriority;
}
export function flushSyncCallbackQueue() {
if(syncQueue){
for (let i = 0; i < syncQueue.length; i++) {
let callback = syncQueue[i];
do {
callback = callback();
} while (callback);
}
syncQueue = null;
}
}
function scheduleSyncCallback(callback) {
if (!syncQueue) {
syncQueue = [callback];
} else {
syncQueue.push(callback);
}
}
function performSyncWorkOnRoot(workInProgress) {
let root = workInProgress;
while (workInProgress) {
if (workInProgress.tag === ClassComponent) {
let inst = workInProgress.stateNode;
inst.state = processUpdateQueue(inst,workInProgress);
workInProgress.stateNode.render();
}
workInProgress = workInProgress.child;
}
commitRoot(root);
}
function processUpdateQueue(inst,workInProgress){
return workInProgress.updateQueue.reduce((state, update) => ({ ...state, ...update.payload }), inst.state);;
}
function commitRoot(root){
root.callbackPriority = NoLanePriority;
}
前三者属于React的优先级机制,第四个属于
scheduler
的优先级机制
src\react\packages\shared\ReactTypes.js
export const DiscreteEvent = 0;
export const UserBlockingEvent = 1;
export const ContinuousEvent = 2;
src\react\packages\scheduler\src\Scheduler.js
function unstable_runWithPriority(priorityLevel, eventHandler) {
switch (priorityLevel) {
case ImmediatePriority:
case UserBlockingPriority:
case NormalPriority:
case LowPriority:
case IdlePriority:
break;
default:
priorityLevel = NormalPriority;
}
var previousPriorityLevel = currentPriorityLevel;
currentPriorityLevel = priorityLevel;
try {
return eventHandler();
} finally {
currentPriorityLevel = previousPriorityLevel;
}
}
schedulerPriority
,然后计算更新优先级src\react\packages\react-reconciler\src\ReactFiberLane.js
const TotalLanes = 31;
export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010;
export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100;
const InputDiscreteLanes: Lanes = /* */ 0b0000000000000000000000000011000;
const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
const InputContinuousLanes: Lanes = /* */ 0b0000000000000000000000011000000;
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000100000000;
export const DefaultLanes: Lanes = /* */ 0b0000000000000000000111000000000;
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionLanes: Lanes = /* */ 0b0000000001111111110000000000000;
const RetryLanes: Lanes = /* */ 0b0000011110000000000000000000000;
export const SomeRetryLane: Lanes = /* */ 0b0000010000000000000000000000000;
export const SelectiveHydrationLane: Lane = /* */ 0b0000100000000000000000000000000;
const NonIdleLanes = /* */ 0b0000111111111111111111111111111;
export const IdleHydrationLane: Lane = /* */ 0b0001000000000000000000000000000;
const IdleLanes: Lanes = /* */ 0b0110000000000000000000000000000;
export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
let currentUpdateLanePriority = NoLanePriority;
export function getCurrentUpdateLanePriority() {
return currentUpdateLanePriority;
}
export function setCurrentUpdateLanePriority(newLanePriority) {
currentUpdateLanePriority = newLanePriority;
}
src\react\packages\react-reconciler\src\ReactFiberLane.js
export const SyncLanePriority: LanePriority = 15;
export const SyncBatchedLanePriority: LanePriority = 14;
const InputDiscreteHydrationLanePriority: LanePriority = 13;
export const InputDiscreteLanePriority: LanePriority = 12;
const InputContinuousHydrationLanePriority: LanePriority = 11;
export const InputContinuousLanePriority: LanePriority = 10;
const DefaultHydrationLanePriority: LanePriority = 9;
export const DefaultLanePriority: LanePriority = 8;
const TransitionHydrationPriority: LanePriority = 7;
export const TransitionPriority: LanePriority = 6;
const RetryLanePriority: LanePriority = 5;
const SelectiveHydrationLanePriority: LanePriority = 4;
const IdleHydrationLanePriority: LanePriority = 3;
const IdleLanePriority: LanePriority = 2;
const OffscreenLanePriority: LanePriority = 1;
export const NoLanePriority: LanePriority = 0;
src\react\packages\react-reconciler\src\SchedulerWithReactIntegration.old.js
export const ImmediatePriority: ReactPriorityLevel = 99;
export const UserBlockingPriority: ReactPriorityLevel = 98;
export const NormalPriority: ReactPriorityLevel = 97;
export const LowPriority: ReactPriorityLevel = 96;
export const IdlePriority: ReactPriorityLevel = 95;
export const NoPriority: ReactPriorityLevel = 90;