diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 3784575..0000000 --- a/src/App.js +++ /dev/null @@ -1,25 +0,0 @@ -import logo from './logo.svg'; -import './App.css'; - -function App() { - return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- ); -} - -export default App; diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 1f03afe..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/index.css b/src/index.css index ec2585e..927821b 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,3 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +.sentence { + background-color: skyblue; } diff --git a/src/index.js b/src/index.js index ef2edf8..ceae22a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,28 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import { Component } from 'react'; +import ReactDOM from './mini-react/react-dom'; import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +class ClassComp extends Component { + render() { + return
this is a class-component
; + } +} -ReactDOM.render( - - - , - document.getElementById('root') -); +function FunctionComp() { + return
this is a function-component
; +} -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); +const jsx = ( +
+ + + <> +
this is a div element
+

this is a p element

+ + zh-lx + {['item1', 'item2', 'item3'].map((item) => { + return
  • {item}
  • ; + })} +
    +); +ReactDOM.render(jsx, document.getElementById('root')); diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/mini-react/react-dom.js b/src/mini-react/react-dom.js new file mode 100644 index 0000000..707aefe --- /dev/null +++ b/src/mini-react/react-dom.js @@ -0,0 +1,92 @@ +function render(element, container) { + const dom = renderDom(element); + container.appendChild(dom); +} + +// 将 React.Element 渲染为真实 dom +function renderDom(element) { + let dom = null; // 最终要返回的 dom + + // 如果 element 本身为 string,表示文本节点,不需要考虑其 props 了,创建后直接返回 + if (typeof element === 'string') { + dom = document.createTextNode(element); + return dom; + } + + // 如果 element 本身为 Array,表示条件渲染,对其子元素转换 dom 后直接返回 + if (Array.isArray(element)) { + dom = document.createDocumentFragment(); + for (let item of element) { + const child = renderDom(item); + dom.appendChild(child); + } + return dom; + } + + // 其他情况除了创建 element 本身对应的 dom,还需要考虑子元素 + const { + type, + props: { children, ...attributes }, + } = element; + + if (typeof type === 'string') { + // type 为 string 表示常规 dom 元素 + dom = document.createElement(type); + } else if (type.toString() === 'Symbol(react.fragment)') { + // React.Fragment 的渲染 + dom = document.createDocumentFragment(); + } else if (typeof type === 'function') { + // type 为 function 表示类组件或者函数组件 + if (type.prototype.isReactComponent) { + // 类组件 + const { props, type: Comp } = element; + const component = new Comp(props); + const jsx = component.render(); + dom = renderDom(jsx); + } else { + // 函数组件 + const { props, type: Comp } = element; + const jsx = Comp(props); + dom = renderDom(jsx); + } + } else { + // 其他情况,暂不考虑 + } + + // 如果 children 存在,递归渲染 children + if (children) { + const childrenDom = renderDom(children); + dom.appendChild(childrenDom); + } + + // 更新 dom 属性 + updateAttributes(dom, attributes); + + return dom; +} + +const updateAttributes = (dom, attributes) => { + Object.keys(attributes).forEach((key) => { + if (key === 'className') { + // className 的处理 + const classes = attributes[key].split(' '); + classes.forEach((classKey) => { + dom.classList.add(classKey); + }); + } else if (key === 'style') { + // style处理 + const style = attributes[key]; + Object.keys(style).forEach((styleKey) => { + dom.style[styleKey] = style[styleKey]; + }); + } else { + // 其他属性的处理 + dom[key] = attributes[key]; + } + }); +}; + +const ReactDOM = { + render, +}; +export default ReactDOM; diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3a..0000000 --- a/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/setupTests.js b/src/setupTests.js deleted file mode 100644 index 8f2609b..0000000 --- a/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom';