mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-15 16:51:37 +00:00
docs(post): update post sandpack
This commit is contained in:
@ -14,15 +14,22 @@ const RUASandpack = ({ ...rest }: Props) => {
|
|||||||
|
|
||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
return (
|
return (
|
||||||
<div className="my-2 min-h-[402px]">
|
<div className="my-2 rounded-[0.5em] overflow-hidden">
|
||||||
<Sandpack {...rest} />
|
<Sandpack
|
||||||
|
{...rest}
|
||||||
|
options={{
|
||||||
|
showConsole: true,
|
||||||
|
showConsoleButton: true,
|
||||||
|
editorHeight: '512px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="my-2 min-h-[402px]">
|
<div className="my-2 rounded-[0.5em] overflow-hidden">
|
||||||
<Sandpack
|
<Sandpack
|
||||||
{...rest}
|
{...rest}
|
||||||
theme={
|
theme={
|
||||||
@ -30,6 +37,12 @@ const RUASandpack = ({ ...rest }: Props) => {
|
|||||||
(theme ?? 'latte') as keyof typeof THEME_CATPUCCIN_MAP
|
(theme ?? 'latte') as keyof typeof THEME_CATPUCCIN_MAP
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
options={{
|
||||||
|
showConsole: true,
|
||||||
|
showConsoleButton: true,
|
||||||
|
editorHeight: '512px',
|
||||||
|
showRefreshButton: true,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -24,6 +24,14 @@ import {
|
|||||||
useSyncExternalStore,
|
useSyncExternalStore,
|
||||||
useTransition,
|
useTransition,
|
||||||
} from './sandpack/react18-new-hooks';
|
} from './sandpack/react18-new-hooks';
|
||||||
|
import {
|
||||||
|
app1,
|
||||||
|
app2,
|
||||||
|
app3,
|
||||||
|
signal1,
|
||||||
|
signal2,
|
||||||
|
signal3,
|
||||||
|
} from './sandpack/automatic-dependency-collect';
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
sandpack: {
|
sandpack: {
|
||||||
@ -58,6 +66,14 @@ const data = {
|
|||||||
MultiStore,
|
MultiStore,
|
||||||
Reducer,
|
Reducer,
|
||||||
},
|
},
|
||||||
|
'automatic-dependency-collect': {
|
||||||
|
signal1,
|
||||||
|
app1,
|
||||||
|
signal2,
|
||||||
|
app2,
|
||||||
|
signal3,
|
||||||
|
app3,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,24 +96,17 @@ const useState: UseState = (value) => {
|
|||||||
|
|
||||||
使用它的方式和官方 hooks 没有区别:
|
使用它的方式和官方 hooks 没有区别:
|
||||||
|
|
||||||
```tsx
|
<RUASandpack
|
||||||
function App() {
|
template="react-ts"
|
||||||
console.log('App updated');
|
files={{
|
||||||
const [count, setCount] = useState(0);
|
'/Button.tsx': {
|
||||||
|
code: sandpack.common.Button,
|
||||||
return (
|
hidden: true,
|
||||||
<>
|
},
|
||||||
<button
|
'/signal.ts': sandpack['automatic-dependency-collect'].signal1,
|
||||||
onClick={() => {
|
'/App.tsx': sandpack['automatic-dependency-collect'].app1,
|
||||||
setCount((d) => d + 1);
|
}}
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
Update {count()}
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### useEffect
|
### useEffect
|
||||||
|
|
||||||
@ -248,6 +241,18 @@ const useEffect = (callback: () => void) => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<RUASandpack
|
||||||
|
template="react-ts"
|
||||||
|
files={{
|
||||||
|
'/Button.tsx': {
|
||||||
|
code: sandpack.common.Button,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
'/signal.ts': sandpack['automatic-dependency-collect'].signal2,
|
||||||
|
'/App.tsx': sandpack['automatic-dependency-collect'].app2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
### useMemo
|
### useMemo
|
||||||
|
|
||||||
通过 `useEffect` 实现的自动依赖追踪,我们就可以轻松的实现一个自动追踪依赖的 `useMemo`:
|
通过 `useEffect` 实现的自动依赖追踪,我们就可以轻松的实现一个自动追踪依赖的 `useMemo`:
|
||||||
@ -259,3 +264,15 @@ const useMemo = <T>(callback: () => T) => {
|
|||||||
return s;
|
return s;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<RUASandpack
|
||||||
|
template="react-ts"
|
||||||
|
files={{
|
||||||
|
'/Button.tsx': {
|
||||||
|
code: sandpack.common.Button,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
'/signal.ts': sandpack['automatic-dependency-collect'].signal3,
|
||||||
|
'/App.tsx': sandpack['automatic-dependency-collect'].app3,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
299
content/sandpack/automatic-dependency-collect.ts
Normal file
299
content/sandpack/automatic-dependency-collect.ts
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
export const signal1 = `import { useRef, useState as useUpdate } from "react";
|
||||||
|
|
||||||
|
export type Getter<T> = () => T;
|
||||||
|
export type Setter<T> = (newValue: T | ((oldValue: T) => T)) => void;
|
||||||
|
export type UseState = <T>(value: T) => [Getter<T>, Setter<T>];
|
||||||
|
|
||||||
|
export const useState: UseState = (value) => {
|
||||||
|
const state = useRef(value);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const [_, update] = useUpdate({});
|
||||||
|
|
||||||
|
const getter: Getter<typeof value> = () => {
|
||||||
|
return state.current;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setter: Setter<typeof value> = (updater) => {
|
||||||
|
const newState =
|
||||||
|
updater instanceof Function ? updater(state.current) : updater;
|
||||||
|
if (state.current === newState) return;
|
||||||
|
state.current = newState;
|
||||||
|
update({});
|
||||||
|
};
|
||||||
|
|
||||||
|
return [getter, setter];
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const app1 = `import { useState } from "./signal";
|
||||||
|
import Button from './Button';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
console.log('App updated');
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setCount((d) => d + 1);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Update {count()}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const signal2 = `/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
import { useRef, useState as useUpdate, useEffect as useMounted } from 'react';
|
||||||
|
|
||||||
|
export type Getter<T> = () => T;
|
||||||
|
export type Setter<T> = (newValue: T | ((oldValue: T) => T)) => void;
|
||||||
|
export type UseState = <T>(value: T) => [Getter<T>, Setter<T>];
|
||||||
|
export type Subs = Set<Effect>;
|
||||||
|
|
||||||
|
export type Effect = {
|
||||||
|
// 用于执行 useEffect 回调函数
|
||||||
|
execute: () => void;
|
||||||
|
// 保存该 useEffect 依赖的 state 对应的 subs 集合
|
||||||
|
deps: Set<Subs>;
|
||||||
|
};
|
||||||
|
const effectStack: Effect[] = [];
|
||||||
|
|
||||||
|
const subscribe = (effect: Effect, subs: Subs) => {
|
||||||
|
// 建立订阅关系
|
||||||
|
subs.add(effect);
|
||||||
|
// 建立依赖关系
|
||||||
|
effect.deps.add(subs);
|
||||||
|
};
|
||||||
|
const useState: UseState = (value) => {
|
||||||
|
const state = useRef(value);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const [_, update] = useUpdate({});
|
||||||
|
|
||||||
|
const subs = useRef(new Set<Effect>());
|
||||||
|
|
||||||
|
const getter: Getter<typeof value> = () => {
|
||||||
|
// 获取刚刚送入栈中的 effect
|
||||||
|
const effect = effectStack[effectStack.length - 1];
|
||||||
|
if (effect) {
|
||||||
|
// 建立订阅发布关系
|
||||||
|
subscribe(effect, subs.current);
|
||||||
|
}
|
||||||
|
return state.current;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setter: Setter<typeof value> = (updater) => {
|
||||||
|
const newState =
|
||||||
|
updater instanceof Function ? updater(state.current) : updater;
|
||||||
|
if (state.current === newState) return;
|
||||||
|
|
||||||
|
state.current = newState;
|
||||||
|
update({});
|
||||||
|
// 通知所有订阅 effect 状态变化
|
||||||
|
for (const sub of [...subs.current]) {
|
||||||
|
sub.execute();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [getter, setter];
|
||||||
|
};
|
||||||
|
|
||||||
|
const cleanup = (effect: Effect) => {
|
||||||
|
for (const subs of effect.deps) {
|
||||||
|
subs.delete(effect);
|
||||||
|
}
|
||||||
|
effect.deps.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
const useEffect = (callback: () => void) => {
|
||||||
|
const execute = () => {
|
||||||
|
// 重制依赖
|
||||||
|
cleanup(effect);
|
||||||
|
// 添加到副作用列表
|
||||||
|
effectStack.push(effect);
|
||||||
|
try {
|
||||||
|
callback();
|
||||||
|
} finally {
|
||||||
|
effectStack.pop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const effect: Effect = {
|
||||||
|
execute,
|
||||||
|
deps: new Set(),
|
||||||
|
};
|
||||||
|
|
||||||
|
useMounted(() => {
|
||||||
|
// 调用时执行
|
||||||
|
execute();
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useState, useEffect };
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const app2 = `import { useState, useEffect } from "./signal";
|
||||||
|
import Button from './Button';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
console.log('App updated');
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
console.log('App updated');
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('count is ', count());
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('effect update');
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setCount((d) => d + 1);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Update {count()}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const signal3 = `/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
import { useRef, useState as useUpdate, useEffect as useMounted } from 'react';
|
||||||
|
|
||||||
|
export type Getter<T> = () => T;
|
||||||
|
export type Setter<T> = (newValue: T | ((oldValue: T) => T)) => void;
|
||||||
|
export type UseState = <T>(value: T) => [Getter<T>, Setter<T>];
|
||||||
|
export type Subs = Set<Effect>;
|
||||||
|
|
||||||
|
export type Effect = {
|
||||||
|
// 用于执行 useEffect 回调函数
|
||||||
|
execute: () => void;
|
||||||
|
// 保存该 useEffect 依赖的 state 对应的 subs 集合
|
||||||
|
deps: Set<Subs>;
|
||||||
|
};
|
||||||
|
const effectStack: Effect[] = [];
|
||||||
|
|
||||||
|
const subscribe = (effect: Effect, subs: Subs) => {
|
||||||
|
// 建立订阅关系
|
||||||
|
subs.add(effect);
|
||||||
|
// 建立依赖关系
|
||||||
|
effect.deps.add(subs);
|
||||||
|
};
|
||||||
|
const useState: UseState = (value) => {
|
||||||
|
const state = useRef(value);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const [_, update] = useUpdate({});
|
||||||
|
|
||||||
|
const subs = useRef(new Set<Effect>());
|
||||||
|
|
||||||
|
const getter: Getter<typeof value> = () => {
|
||||||
|
// 获取刚刚送入栈中的 effect
|
||||||
|
const effect = effectStack[effectStack.length - 1];
|
||||||
|
if (effect) {
|
||||||
|
// 建立订阅发布关系
|
||||||
|
subscribe(effect, subs.current);
|
||||||
|
}
|
||||||
|
return state.current;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setter: Setter<typeof value> = (updater) => {
|
||||||
|
const newState =
|
||||||
|
updater instanceof Function ? updater(state.current) : updater;
|
||||||
|
if (state.current === newState) return;
|
||||||
|
|
||||||
|
state.current = newState;
|
||||||
|
update({});
|
||||||
|
// 通知所有订阅 effect 状态变化
|
||||||
|
for (const sub of [...subs.current]) {
|
||||||
|
sub.execute();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [getter, setter];
|
||||||
|
};
|
||||||
|
|
||||||
|
const cleanup = (effect: Effect) => {
|
||||||
|
for (const subs of effect.deps) {
|
||||||
|
subs.delete(effect);
|
||||||
|
}
|
||||||
|
effect.deps.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
const useEffect = (callback: () => void) => {
|
||||||
|
const execute = () => {
|
||||||
|
// 重制依赖
|
||||||
|
cleanup(effect);
|
||||||
|
// 添加到副作用列表
|
||||||
|
effectStack.push(effect);
|
||||||
|
try {
|
||||||
|
callback();
|
||||||
|
} finally {
|
||||||
|
effectStack.pop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const effect: Effect = {
|
||||||
|
execute,
|
||||||
|
deps: new Set(),
|
||||||
|
};
|
||||||
|
|
||||||
|
useMounted(() => {
|
||||||
|
// 调用时执行
|
||||||
|
execute();
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useMemo = <T>(callback: () => T) => {
|
||||||
|
const [s, set] = useState(callback());
|
||||||
|
useEffect(() => set(callback()));
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useState, useEffect, useMemo };
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const app3 = `import { useState, useEffect, useMemo } from "./signal";
|
||||||
|
import Button from './Button';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
console.log('App updated');
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
console.log('App updated');
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('count is ', count());
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('effect update');
|
||||||
|
});
|
||||||
|
|
||||||
|
const double = useMemo(() => count() * 2);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setCount((d) => d + 1);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Update {count()}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button disabled>
|
||||||
|
Double {double()}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
`;
|
Reference in New Issue
Block a user