# react-source-code
**Repository Path**: BruceLluo/react-source-code
## Basic Information
- **Project Name**: react-source-code
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-02-24
- **Last Updated**: 2024-03-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# [React](https://react.dev/) · [](https://github.com/facebook/react/blob/main/LICENSE) [](https://www.npmjs.com/package/react) [](https://circleci.com/gh/facebook/react) [](https://legacy.reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
React is a JavaScript library for building user interfaces.
* **Declarative:** React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep the state out of the DOM.
* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using [React Native](https://reactnative.dev/).
[Learn how to use React in your project](https://react.dev/learn).
## Installation
React has been designed for gradual adoption from the start, and **you can use as little or as much React as you need**:
* Use [Quick Start](https://react.dev/learn) to get a taste of React.
* [Add React to an Existing Project](https://react.dev/learn/add-react-to-an-existing-project) to use as little or as much React as you need.
* [Create a New React App](https://react.dev/learn/start-a-new-react-project) if you're looking for a powerful JavaScript toolchain.
## Documentation
You can find the React documentation [on the website](https://react.dev/).
Check out the [Getting Started](https://react.dev/learn) page for a quick overview.
The documentation is divided into several sections:
* [Quick Start](https://react.dev/learn)
* [Tutorial](https://react.dev/learn/tutorial-tic-tac-toe)
* [Thinking in React](https://react.dev/learn/thinking-in-react)
* [Installation](https://react.dev/learn/installation)
* [Describing the UI](https://react.dev/learn/describing-the-ui)
* [Adding Interactivity](https://react.dev/learn/adding-interactivity)
* [Managing State](https://react.dev/learn/managing-state)
* [Advanced Guides](https://react.dev/learn/escape-hatches)
* [API Reference](https://react.dev/reference/react)
* [Where to Get Support](https://react.dev/community)
* [Contributing Guide](https://legacy.reactjs.org/docs/how-to-contribute.html)
You can improve it by sending pull requests to [this repository](https://github.com/reactjs/reactjs.org).
## Examples
We have several examples [on the website](https://react.dev/). Here is the first one to get you started:
```jsx
import { createRoot } from 'react-dom/client';
function HelloMessage({ name }) {
return
Hello {name}
;
}
const root = createRoot(document.getElementById('container'));
root.render();
```
This example will render "Hello Taylor" into a container on the page.
You'll notice that we used an HTML-like syntax; [we call it JSX](https://react.dev/learn#writing-markup-with-jsx). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML.
## Contributing
The main purpose of this repository is to continue evolving React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React.
### [Code of Conduct](https://code.fb.com/codeofconduct)
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
### [Contributing Guide](https://legacy.reactjs.org/docs/how-to-contribute.html)
Read our [contributing guide](https://legacy.reactjs.org/docs/how-to-contribute.html) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React.
### Good First Issues
To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first issues](https://github.com/facebook/react/labels/good%20first%20issue) that contain bugs that have a relatively limited scope. This is a great place to get started.
### License
React is [MIT licensed](./LICENSE).
# React常见api
## React 入口
packages/react/index.js
## ReactElement
packages/react/src/ReactClient.js
ReactElement通过React.createElement(type,config,children)创建
```js
// type - React Element 类型, such as HostComponent PureComponent Functional Component , react原生提供的Fragment
// config - 要设置的元素的公共对象属性, 如key, ref,attrs,但key和ref不会与其他属性一起处理会分开单独处理
// children - 元素的子节点,或子节点数组
export function createElement(type, config, children) {
// 处理参数
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner,
};
return element
}
```
ReactElement只是一个用来承载信息的容器,他会告诉后续的操作这个节点的以下信息:
1. type类型,用于判断如何创建节点
2. key和ref这些特殊信息
3. props新的属性内容
4. '$$typeof用于确定是否属于ReactElement'
## 类组件中的Component 和 PureComponent
packages/react/src/ReactBaseClasses.js
```js
function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
/**
* Convenience component with default shallow equality check for sCU.
*/
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// Avoid an extra prototype jump for these methods.
assign(pureComponentPrototype, Component.prototype);
// 这里就是Component 跟 PureReactComponent 的不同,多了一个标识isPureReactComponent
pureComponentPrototype.isPureReactComponent = true;
```
有标识isPureReactComponent来判断类组件是否需要更新
```js
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
```
## ReactCreateRef
createRef 创建一个不可变的ref对象
```js
// an immutable object with a single mutable value
export function createRef(): RefObject {
const refObject = {
current: null,
};
if (__DEV__) {
Object.seal(refObject);
}
return refObject;
}
```
## fowardRef
forwardRef是用来解决HOC组件传递ref的问题
```js
export function forwardRef(
render: (props: Props, ref: React$Ref) => React$Node,
) {
// ...
const elementType = {
$$typeof: REACT_FORWARD_REF_TYPE,
render,
};
// ...
return elementType;
}
```
## createContext
返回一个context
context.Provider , context.Consumer
```js
export function createContext(defaultValue: T): ReactContext {
// TODO: Second argument used to be an optional `calculateChangedBits`
// function. Warn to reserve for future use?
const context: ReactContext = {
$$typeof: REACT_CONTEXT_TYPE,
// As a workaround to support multiple concurrent renderers, we categorize
// some renderers as primary and others as secondary. We only expect
// there to be two concurrent renderers at most: React Native (primary) and
// Fabric (secondary); React DOM (primary) and React ART (secondary).
// Secondary renderers store their context values on separate fields.
_currentValue: defaultValue,
_currentValue2: defaultValue,
// Used to track how many concurrent renderers this context currently
// supports within in a single renderer. Such as parallel server rendering.
_threadCount: 0,
// These are circular
Provider: (null: any),
Consumer: (null: any),
};
if (enableRenderableContext) {
context.Provider = context;
context.Consumer = {
$$typeof: REACT_CONSUMER_TYPE,
_context: context,
};
} else {
(context: any).Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context,
};
if (__DEV__) {
// ...
} else {
// context.Consumer指向context本身,方便后面取_currentValue
(context: any).Consumer = context;
}
}
if (__DEV__) {
context._currentRenderer = null;
context._currentRenderer2 = null;
}
return context;
}
```
## ReactMemo
类组件通过包裹memo函数并传入compare函数来实现PureComponent的功能
浅比较props来判断是否需要更新。
```js
export function memo(
type: React$ElementType,
compare?: (oldProps: Props, newProps: Props) => boolean,
) {
if (__DEV__) {
if (!isValidElementType(type)) {
console.error(
'memo: The first argument must be a component. Instead ' +
'received: %s',
type === null ? 'null' : typeof type,
);
}
}
const elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
if (__DEV__) {
// ...
}
return elementType;
}
```
# React中的更新
## 创建更新的方法
1. ReactDom.render || hydrate
2. setState
3. forceUpdate
### ReactDom.render
/Users/bruceluo/Desktop/Study/react-source-code/packages/react-dom/src/client/ReactDOM.js
创建ReactRoot
创建FiberRoot,RootFiber
创建更新
ReactDom.render 18之前
ReactDom.createRoot 18以后 /Users/bruceluo/Desktop/Study/react-source-code/packages/react-dom/src/client/ReactDOMRoot.js
```jsx
/**
* element 元素 如:
* container 容器载体 如:dom.getElementById('root')
*/
export function render(
element: React$Element,
container: Container,
callback: ?Function,
): React$Component | PublicInstance | null {
if (__DEV__) {
console.error(
'ReactDOM.render is no longer supported in React 18. Use createRoot ' +
'instead. Until you switch to the new API, your app will behave as ' +
"if it's running React 17. Learn " +
'more: https://reactjs.org/link/switch-to-createroot',
);
}
if (!isValidContainerLegacy(container)) {
throw new Error('Target container is not a DOM element.');
}
if (__DEV__) {
const isModernRoot =
isContainerMarkedAsRoot(container) &&
container._reactRootContainer === undefined;
if (isModernRoot) {
console.error(
'You are calling ReactDOM.render() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. ' +
'Did you mean to call root.render(element)?',
);
}
}
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}
/**
* forceHydrate 水合,服务端使用,方便调和节点是否可以重复使用
*/
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component,
children: ReactNodeList,
container: Container,
forceHydrate: boolean,
callback: ?Function,
): React$Component | PublicInstance | null {
if (__DEV__) {
topLevelUpdateWarnings(container);
warnOnInvalidCallback(callback === undefined ? null : callback, 'render');
}
const maybeRoot = container._reactRootContainer;
let root: FiberRoot;
// 初始化没有_reactRootContainer
if (!maybeRoot) {
// Initial mount
// 创建容器的根节点
root = legacyCreateRootFromDOMContainer(
container,
children,
parentComponent,
callback,
forceHydrate,
);
} else {
root = maybeRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function () {
const instance = getPublicRootInstance(root);
originalCallback.call(instance);
};
}
// Update
updateContainer(children, root, parentComponent, callback);
}
return getPublicRootInstance(root);
}
// packages/react-reconciler/src/ReactFiberReconciler.js
export function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component,
callback: ?Function,
): Lane {
if (__DEV__) {
onScheduleRoot(container, element);
}
const current = container.current;
// 更新优先级
const lane = requestUpdateLane(current);
if (enableSchedulingProfiler) {
markRenderScheduled(lane);
}
const context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
if (__DEV__) {
if (
ReactCurrentFiberIsRendering &&
ReactCurrentFiberCurrent !== null &&
!didWarnAboutNestedUpdates
) {
didWarnAboutNestedUpdates = true;
console.error(
'Render methods should be a pure function of props and state; ' +
'triggering nested component updates from render is not allowed. ' +
'If necessary, trigger nested updates in componentDidUpdate.\n\n' +
'Check the render method of %s.',
getComponentNameFromFiber(ReactCurrentFiberCurrent) || 'Unknown',
);
}
}
// 标记更新
const update = createUpdate(lane);
// Caution: React DevTools currently depends on this property
// being called "element".
update.payload = {element};
callback = callback === undefined ? null : callback;
if (callback !== null) {
if (__DEV__) {
if (typeof callback !== 'function') {
console.error(
'render(...): Expected the last optional `callback` argument to be a ' +
'function. Instead received: %s.',
callback,
);
}
}
update.callback = callback;
}
const root = enqueueUpdate(current, update, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, current, lane);
entangleTransitions(root, current, lane);
}
return lane;
}
// packages/react-reconciler/src/ReactFiberClassUpdateQueue.js
// 更新加入队列
export function enqueueUpdate(
fiber: Fiber,
update: Update,
lane: Lane,
): FiberRoot | null {
const updateQueue = fiber.updateQueue;
if (updateQueue === null) {
// Only occurs if the fiber has been unmounted.
return null;
}
const sharedQueue: SharedQueue = (updateQueue: any).shared;
if (__DEV__) {
if (
currentlyProcessingQueue === sharedQueue &&
!didWarnUpdateInsideUpdate
) {
const componentName = getComponentNameFromFiber(fiber);
console.error(
'An update (setState, replaceState, or forceUpdate) was scheduled ' +
'from inside an update function. Update functions should be pure, ' +
'with zero side-effects. Consider using componentDidUpdate or a ' +
'callback.\n\nPlease update the following component: %s',
componentName,
);
didWarnUpdateInsideUpdate = true;
}
}
if (isUnsafeClassRenderPhaseUpdate(fiber)) {
// This is an unsafe render phase update. Add directly to the update
// queue so we can process it immediately during the current render.
const pending = sharedQueue.pending;
if (pending === null) {
// This is the first update. Create a circular list.
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
sharedQueue.pending = update;
// Update the childLanes even though we're most likely already rendering
// this fiber. This is for backwards compatibility in the case where you
// update a different component during render phase than the one that is
// currently renderings (a pattern that is accompanied by a warning).
return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane);
} else {
return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane);
}
}
// packages/react-reconciler/src/ReactFiberConcurrentUpdates.js
// 将并发类更新加入队列
export function enqueueConcurrentClassUpdate(
fiber: Fiber,
queue: ClassQueue,
update: ClassUpdate,
lane: Lane,
): FiberRoot | null {
const concurrentQueue: ConcurrentQueue = (queue: any);
const concurrentUpdate: ConcurrentUpdate = (update: any);
enqueueUpdate(fiber, concurrentQueue, concurrentUpdate, lane);
return getRootForUpdatedFiber(fiber);
}
```