Skip to content

Commit e727583

Browse files
yisardependabot[bot]inokawasuchangvjuzhiyuan
authored
fre2: New reconcilation algorithm (#200)
* first rendering * first time is ok * ototype * remove types * mplete * kkkkkk * mplete * new reconcilation * update readme * Update README.md * fix s * some case * Update README.md * Bump node-notifier from 8.0.0 to 8.0.1 (#194) Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/mikaelbr/node-notifier/releases) - [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md) - [Commits](mikaelbr/node-notifier@v8.0.0...v8.0.1) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix typo in README.md (#196) * fix diff bug * fix diff bug * finish diff * finish diff * finish diff * fix bug * fix many bugs * something went right * passed all tests * Update README.md (#197) 拼写错误 * docs: fix typo (#198) * simplify * fix bug * reduce woords * change words * simplify * simplify Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: inokawa <[email protected]> Co-authored-by: Changhao Zhao (赵昌浩) <[email protected]> Co-authored-by: suchangv <[email protected]> Co-authored-by: 琚致远 <[email protected]>
1 parent 64d075a commit e727583

15 files changed

+351
-181
lines changed

README.md

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<p align="center"><img src="http://wx2.sinaimg.cn/mw690/0060lm7Tly1ftpm5b3ihfj3096097aaj.jpg" alt="fre logo" width="150"></p>
22
<h1 align="center">Fre</h1>
3-
<p align="center">:ghost: Tiny React like framework with Concurrent.</p>
3+
<p align="center">:ghost: Tiny Coroutine framework with Fiber.</p>
44
<p align="center">
55
<a href="https://github.com/yisar/fre/actions"><img src="https://img.shields.io/github/workflow/status/yisar/fre/main.svg" alt="Build Status"></a>
66
<a href="https://codecov.io/gh/yisar/fre"><img src="https://img.shields.io/codecov/c/github/yisar/fre.svg" alt="Code Coverage"></a>
@@ -9,17 +9,12 @@
99
<a href="https://bundlephobia.com/result?p=fre"><img src="http://img.badgesize.io/https://unpkg.com/fre/dist/fre.js?compression=brotli&label=brotli" alt="brotli"></a>
1010
</p>
1111

12-
### Feature
1312

14-
- :tada: Functional Component and hooks API
15-
- :confetti_ball: Time slicing and Algebraic effects
16-
- :telescope: keyed reconcilation algorithm
13+
- **Coroutine with Fiber** — This is an amazing idea, which implements the coroutine scheduler in JavaScript, and the rendering is asynchronous, which supports Time slicing and suspense components.
1714

18-
### Real world
15+
- **Highly-optimized algorithm** — Fre has a better reconciliation algorithm, which traverses from both ends with O (n) complexity, and supports keyed.
1916

20-
[clicli.me](https://www.clicli.me)
21-
22-
Any other demos [click here](https://github.com/yisar/fre/tree/master/demo/src)
17+
- **Do more with less** — After tree shaking, project of hello world is only 1KB, but it has most fetures, virtual DOM, hooks API, functional component and more.
2318

2419
### Use
2520

@@ -59,8 +54,6 @@ render(<App />, document.getElementById('root'))
5954

6055
- [useRef](https://github.com/yisar/fre#useref)
6156

62-
- [useContext](https://github.com/yisar/fre#usecontext)
63-
6457
#### useState
6558

6659
`useState` is a base API, It will receive initial state and return a Array
@@ -102,7 +95,7 @@ function App() {
10295
<div>
10396
{state.count}
10497
<button onClick={() => dispatch({ type: 'up' })}>+</button>
105-
<button onClick={() => dispatch({ type: 'down' })}>+</button>
98+
<button onClick={() => dispatch({ type: 'down' })}>-</button>
10699
</div>
107100
)
108101
}
@@ -138,15 +131,15 @@ If it return a function, the function can do cleanups:
138131
```js
139132
useEffect(() => {
140133
document.title = 'count is ' + count
141-
reutn () => {
134+
return () => {
142135
store.unsubscribe()
143136
}
144137
}, [])
145138
```
146139

147140
#### useLayout
148141

149-
More like useEffect, but useEffect queue in `requestAnimationFrame`, but useLayout is sync and block commitWork.
142+
More like useEffect, but useLayout is sync and blocking UI.
150143

151144
```js
152145
useLayout(() => {
@@ -156,7 +149,7 @@ useLayout(() => {
156149

157150
#### useMemo
158151

159-
`useMemo` has the same parameters as `useEffect`, but `useMemo` will return a cached value.
152+
`useMemo` has the same rules as `useEffect`, but `useMemo` will return a cached value.
160153

161154
```js
162155
function App() {
@@ -234,19 +227,5 @@ The above code needs babel plugin `@babel/plugin-transform-react-jsx`
234227
]
235228
```
236229

237-
#### time slicing
238-
239-
Time slicing is the scheduling of reconcilation, synchronous tasks, sacrifice CPU and reduce blocking time
240-
241-
#### resumable exception
242-
243-
resumable exception is a concept of algebraic effects. It can synchronously throw effects and then resume the execution of other logic of components.
244-
245-
#### key-based reconcilation
246-
247-
Fre implements a compact reconcilation algorithm support keyed, which also called diff.
248-
249-
It uses hash to mark locations to reduce much size.
250-
251230
#### License
252231
_MIT @yisar

demo/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<body>
1212
<div id="root"></div>
13-
<script src="./src/use-state.tsx"></script>
13+
<script src="./src/ref.tsx"></script>
1414
</body>
1515

1616
</html>

demo/src/keys.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { h, render, useEffect, useState } from '../../src/index'
2+
3+
// function App() {
4+
// const [key, setKey] = useState(['a', 'b', 'c'])
5+
// return [
6+
// <button onClick={() => setKey(['a', 'c', 'b','d'])}>x</button>,
7+
// <ul>
8+
// {key.map((i) => (
9+
// <li key={i}>{i}</li>
10+
// ))}
11+
// </ul>,
12+
// ]
13+
// }
14+
15+
// function App() {
16+
// const [key, setKey] = useState(['a', 'b', 'c'])
17+
// return [
18+
// <button onClick={() => setKey(['b', 'c', 'a'])}>x</button>,
19+
// <ul>
20+
// {key.map((i) => (
21+
// <li key={i}>{i}</li>
22+
// ))}
23+
// </ul>,
24+
// ]
25+
// }
26+
27+
// function App() {
28+
// const [key, setKey] = useState(['a', 'b', 'c'])
29+
// return [
30+
// <button onClick={() => setKey(['c', 'b','a'])}>x</button>,
31+
// <ul>
32+
// {key.map((i) => (
33+
// <li key={i}>{i}</li>
34+
// ))}
35+
// </ul>,
36+
// ]
37+
// }
38+
39+
function App() {
40+
const [key, setKey] = useState([1, 2])
41+
return [
42+
<button onClick={() => setKey([3, 2, 1])}>x</button>,
43+
<ul>
44+
{key.map((i) => (
45+
<Li i={i} key={i} />
46+
// <li key={i}>{i}</li>
47+
))}
48+
</ul>,
49+
]
50+
}
51+
52+
function Li(props) {
53+
return <li>{props.i}</li>
54+
}
55+
56+
render(<App />, document.getElementById('root'))

demo/src/ref.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/** @jsx h */
2+
3+
// // preact:
4+
// import { render, createElement as h } from "preact/compat";
5+
// import { useState, useEffect } from "preact/hooks";
6+
7+
// react:
8+
// import { createElement as h, useState, useEffect } from "react";
9+
// import { render } from "react-dom";
10+
11+
// // fre:
12+
import { render, h, useState, useEffect, useRef } from '../../src'
13+
14+
15+
const Wrapper = () => {
16+
const [showApp, setShowApp] = useState(true)
17+
18+
useEffect(()=>{
19+
setTimeout(() => {
20+
setShowApp(false)
21+
}, 2000)
22+
},[])
23+
24+
const p = dom => {
25+
if (dom) {
26+
} else {
27+
console.log(111)
28+
}
29+
}
30+
const c = dom => {
31+
if (dom) {
32+
} else {
33+
console.log(222)
34+
}
35+
}
36+
console.log(showApp)
37+
38+
return showApp ? <div ref={p}>
39+
<p ref={c}>before</p>
40+
</div> : <p>App removed...</p>
41+
}
42+
43+
render(<Wrapper />, document.getElementById('root'))

demo/src/use-effect.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import { h, render, useState, useEffect } from '../../src'
77
function Counter({ id, remove }) {
88
const [count, setCount] = useState(0)
99

10-
useEffect(() => {
11-
console.log(`111`)
12-
13-
return () => {
14-
console.log(`222`)
15-
}
16-
})
10+
// useEffect(() => {
11+
// console.log(`111`)
12+
// return () => {
13+
// console.log(`222`)
14+
// }
15+
// })
1716

1817
return (
1918
<div>

demo/src/use-layout.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { h, render, useState, useEffect, useLayoutEffect } from '../../src'
2+
3+
function App() {
4+
const [count, setCount] = useState(0)
5+
return (
6+
<div>
7+
{count < 5 && <A count={count < 1 ? count : 2} />}
8+
<h1>{count}</h1>
9+
<button onClick={() => setCount(count + 1)}>+</button>
10+
</div>
11+
)
12+
}
13+
14+
function A(props) {
15+
useLayoutEffect(() => {
16+
console.log(333)
17+
return () => {
18+
console.log(444)
19+
}
20+
})
21+
return <div>{props.count}</div>
22+
}
23+
24+
render(<App />, document.body)

demo/src/use-state.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function App() {
55
// const [two, setTwo] = useState(0)
66
return (
77
<div>
8-
<button onClick={() => setCount(count + 1)}>{count}</button>
8+
<button onClick={() => setCount(count + 1)}>{count}{count}</button>
99
</div>
1010
)
1111
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
],
2323
"scripts": {
2424
"test": "jest --coverage",
25+
"ref": "jest ./test/ref.test.tsx",
2526
"build": "rollup -c && gzip-size dist/fre.js",
2627
"build:compat": "rollup --config compat/rollup.config.js",
2728
"dev": "rollup -c --watch",

src/dom.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ export const updateElement = <P extends Attributes>(
2121
if (oldValue) dom.removeEventListener(name, oldValue)
2222
dom.addEventListener(name, newValue)
2323
} else if (name in dom && !(dom instanceof SVGElement)) {
24-
// for property, such as className
2524
;(dom as any)[name] = newValue || ''
2625
} else if (newValue == null || newValue === false) {
2726
dom.removeAttribute(name)
2827
} else {
29-
// for attributes
3028
dom.setAttribute(name, newValue)
3129
}
3230
}
@@ -36,7 +34,7 @@ export const createElement = <P = Attributes>(fiber: IFiber) => {
3634
const dom =
3735
fiber.type === 'text'
3836
? document.createTextNode('')
39-
: fiber.op & (1 << 4)
37+
: fiber.tag & (1 << 4)
4038
? document.createElementNS(
4139
'http://www.w3.org/2000/svg',
4240
fiber.type as string

src/hooks.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ export const useReducer = <S, A>(reducer?: Reducer<S, A>, initState?: S): [S, Di
1515
hook[0] = isFn(hook[1]) ? hook[1](hook[0]) : hook.length ? hook[1] : initState
1616
return [
1717
hook[0] as S,
18-
(action: A | Dispatch<A>) => {
19-
hook[1] = reducer ? reducer(hook[0], action as A) : action
20-
hook[2] = reducer && (action as any).type[0] === '*' ? 0b1100 : 0b1000
18+
(value: A | Dispatch<A>) => {
19+
hook[1] = reducer || value
2120
dispatchUpdate(current)
2221
},
2322
]
@@ -67,5 +66,5 @@ export const getHook = <S = Function | undefined, Dependency = any>(cursor: numb
6766
}
6867

6968
export const isChanged = (a: DependencyList, b: DependencyList) => {
70-
return !a || a.length !== b.length || b.some((arg, index) => arg !== a[index])
69+
return !a || b.some((arg, index) => arg !== a[index])
7170
}

0 commit comments

Comments
 (0)