Skip to content

Commit f9c6148

Browse files
updated the readme and the build
1 parent ddac7fe commit f9c6148

File tree

9 files changed

+1119
-793
lines changed

9 files changed

+1119
-793
lines changed

build/refract.cjs.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/refract.es.js

Lines changed: 800 additions & 775 deletions
Large diffs are not rendered by default.

build/refract.umd.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { BaseSignal } from '../signals/signal';
2-
export declare function setCurrentFC(fc: any): void;
2+
import { Fiber } from '../types';
3+
export declare function setCurrentFC(fc: Fiber): void;
34
export declare function clearCurrentFC(): void;
4-
export declare function getCurrentFC(): null;
5+
export declare function getCurrentFC(): Fiber | null;
6+
export declare function runAllEffects(FC: Fiber): void;
57
export declare function cleanUp(fn: Function): void;
8+
export declare function cleanUpWFiber(fn: Function, fiber: Fiber): void;
69
export declare function addEffect(fn: Function): void;
710
export declare function addSignal(signal: BaseSignal<any>): void;
811
export declare function cleanUpFC(currentFC: any, props: any): void;

build/signals/batch.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Fiber } from '../types';
2-
export declare function addEffectCleanup(fn: Function): void;
32
export declare function batchUpdate(cb: Function): void;
43
export declare function setReactiveFunction(fn: Function, fiber: Fiber): void;
54
export declare function setReactiveAttributes(fn: Function, dom: HTMLElement | Text): void;

build/signals/signal.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { Fiber } from '../types';
12
export declare function reactive(fn: Function): any;
23
export declare function reactiveAttribute(fn: Function): any;
34
export declare function createEffect(fn: Function): void;
5+
export declare function runEffect(effect: Function, fiber?: Fiber): void;
46
declare function computed<T extends NormalSignal | any[] | Record<any, any>>(fn: () => T): {
57
readonly value: DeepReadonly<T>;
68
};

readme.md

Lines changed: 273 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@ You can use
5454
`createSignal()`
5555
to create signals and access the signal's value using `signal.value`
5656

57+
#### Syntax:
58+
59+
```jsx
60+
const signal = createSignal(initialValue);
61+
62+
signal.value; // This is a readonly value that must be used if you want to make reactive nodes
63+
signal.update(newValue); // update the value to a newValue
64+
signal.update((prev) => {
65+
// mutate the previous value if it is a array or object.
66+
// or
67+
// return a new value if it is a primitive.
68+
});
69+
```
70+
71+
#### Note:
72+
73+
>
74+
75+
- You cannot update signal values into different types ie., `You cannot update a array value to a object value or a primitive and vice-versa`.
76+
77+
- Primitive Values includes the following: `String, Number, Boolean, undefined, null and Error`.
78+
- These values can be updated into one another ie., `a number signal can be updated to any of the above types`.
79+
5780
```jsx
5881
import { createSignal } from "refract-js";
5982

@@ -76,14 +99,44 @@ function Counter() {
7699
export default Counter;
77100
```
78101

102+
### Computed Values
103+
104+
The built-in `computed` function creates a state that automatically updates whenever its dependent signals change.
105+
106+
> This behaves similarly to React's `useMemo` hook but doesn't require specifying a dependency array.
107+
108+
```jsx
109+
import { createSignal, computed } from "refract-js";
110+
111+
function Counter() {
112+
const count = createSignal(0);
113+
const double = computed(() => count.value * 2);
114+
115+
return (
116+
<div>
117+
{/* Functions for dynamically accessing signal-based values */}
118+
<p>Count: {() => count.value}</p>
119+
<p>Double: {() => double.value}</p>
120+
121+
{/* Use the update function to modify count.value */}
122+
<button onClick={() => count.update((prev) => prev + 1)}>
123+
Increment
124+
</button>
125+
</div>
126+
);
127+
}
128+
129+
export default Counter;
130+
```
131+
79132
### Effects
80133

81134
Effects can be created using the `createEffect` function.
82135

83-
- Effect runs after the components has been mounted to the dom.
84-
- You don't need to declare dependency array as dependencies are automatically tracked.
85-
- Effect re-runs whenever the signals used inside the effect are updated using the update function.
86-
- The cleanup function that is returned from the effect will run when the component unmounts or when the effect is rerun.
136+
- An effect runs after the component has mounted to the DOM.
137+
- You don't need to specify a dependency arraydependencies are automatically tracked.
138+
- The effect re-runs whenever the signals used inside it are updated via the `update` function.
139+
- If the effect returns a cleanup function, it runs when the component unmounts or before the effect re-runs.
87140

88141
```jsx
89142
import { createSignal, createEffect } from "refract-js";
@@ -96,35 +149,243 @@ function TimerComponent() {
96149
seconds.update((prev) => prev + 1);
97150
}, 1000);
98151

99-
// Cleanup function to clear the interval when the component unmounts or the seconds.value is updated
152+
// Cleanup function to clear the interval when the component unmounts or the effect re-runs
100153
return () => clearInterval(interval);
101154
});
102155

103156
createEffect(() => {
104-
// This effect only runs once after the component mounts.
157+
// This effect runs once after the component mounts.
105158

106159
return () => {
107-
// this cleanup will only run when the component mounts
160+
// Cleanup runs only when the component unmounts
108161
};
109162
});
110163

111-
return <p>Elapsed Time: {seconds} seconds</p>;
164+
return <p>Elapsed Time: {() => seconds.value} seconds</p>;
165+
}
166+
```
167+
168+
### Cleanup in Functional Components
169+
170+
The built-in `cleanUp` function allows you to define cleanup logic for any functional component.
171+
Since functional components only render once, any logic can be written inline for better clarity.
172+
173+
```jsx
174+
import { createSignal, cleanUp } from "refract-js";
175+
176+
function AlternateTimerComponent() {
177+
const seconds = createSignal(0);
178+
179+
// Since the component renders once, logic can be written synchronously
180+
const interval = setInterval(() => {
181+
seconds.update((prev) => prev + 1);
182+
}, 1000);
183+
184+
// Cleanup function to clear the interval when the component unmounts
185+
cleanUp(() => {
186+
clearInterval(interval);
187+
});
188+
189+
return <p>Elapsed Time: {() => seconds.value} seconds</p>;
112190
}
113191
```
114192

193+
### Ref's for dom elements
194+
195+
Use the `createRef` function to create references to dom elements.
196+
197+
- The `ref.current` is null until the component has rendered.
198+
- `ref.current` property is defined when inside a effect or inside any event listener.
199+
200+
```jsx
201+
import { createEffect, createRef } from "refract-js";
202+
203+
export default function Form() {
204+
const inputRef = createRef();
205+
206+
createEffect(() => {
207+
console.log(inputRef.current); // it is defined here
208+
});
209+
210+
function handleClick() {
211+
inputRef.current.focus(); // is is defined here
212+
}
213+
214+
console.log(inputRef.current); // prints null to the console
215+
216+
return (
217+
<>
218+
<input ref={inputRef} />
219+
<button onClick={handleClick}>Focus the input</button>
220+
</>
221+
);
222+
}
223+
```
224+
225+
### Handling Asynchronous Tasks
226+
227+
The `createPromise` function allows handling promises and asynchronous tasks with ease.
228+
229+
#### Syntax:
230+
231+
```jsx
232+
type Data = {
233+
// typedata
234+
}
235+
const getData = async () => {
236+
const data = await fetch(...)
237+
238+
return data as Data;
239+
};
240+
241+
const promise = createPromise(getData);
242+
243+
promise.data; // Data | null
244+
245+
promise.error; // Error | null
246+
247+
promise.status; // "pending" || "resolved" || "rejected"
248+
```
249+
250+
#### Example:
251+
252+
```jsx
253+
import { createPromise } from "refract-js";
254+
255+
const getUser = async () => {
256+
try {
257+
const response = await axios.get("https://jsonplaceholder.typicode.com/users/1");
258+
return response.data.username;
259+
} catch (err) {
260+
throw new Error("Cannot fetch User. Error: " + (err as Error).message);
261+
}
262+
};
263+
const Users = () => {
264+
const promise = createPromise(getUser);
265+
266+
return (
267+
<div>
268+
{() => {
269+
if (promise.value.data) {
270+
return <div>{promise.value.data}</div>;
271+
}
272+
if (promise.value.error) {
273+
return <div>{promise.value.error.message}</div>;
274+
}
275+
return <div>Loading...</div>;
276+
}}
277+
</div>
278+
);
279+
};
280+
281+
export default Users;
282+
```
283+
284+
### Lazy Loading Components
285+
286+
You can use the built-in `lazy` function to load components only when they are needed. This improves initial load times and enables a smoother user experience by displaying a pending UI while the component loads.
287+
288+
> Note: Lazy loading only works for loading functional components.
289+
> Important Points:
290+
291+
- The `lazy` function returns another functional component that wraps your imported component.
292+
- The new component has two extra props `errorFallback` and `fallback`.
293+
- `fallback` takes another component or jsx as a fallback UI while the component loads.
294+
- `errorFallback` takes a fallback component or a function with the error as argument ie.,
295+
296+
```jsx
297+
errorFallback = {(error)=><div>{error.message}</div>}
298+
```
299+
300+
Example:
301+
302+
```jsx
303+
import { lazy } from "refract-js";
304+
305+
const Component = lazy(() => import("./Component.tsx"));
306+
307+
const App = ()=>{
308+
309+
return (
310+
311+
<div>
312+
<Component otherProps = {...} fallback = {<div>Loading...</div>} errorFallback = {(error)=><div>{error.message}</div>} />
313+
</div>
314+
)
315+
}
316+
317+
```
318+
319+
### Context/Global State
320+
321+
Refract doesn’t come with a built-in way to create context or global state—but who needs that when you can just toss your signals into a separate file and import them wherever you want? It works exactly as expected. It’s just JavaScript, so why overcomplicate things? 🤷‍♂️
322+
115323
## API Reference
116324

117325
### `createElement(type, props, ...children)`
118326

119-
Creates a virtual DOM element.
327+
Creates a virtual DOM element. This function is used internally by JSX to convert JSX syntax into virtual DOM representations.
120328

121329
### `render(element, container)`
122330

123-
Renders a JSX component to the DOM.
331+
Renders a JSX component to the DOM. It takes a JSX element and a container DOM node as parameters.
332+
333+
### `createSignal(initialValue)`
334+
335+
Creates a signal for state management.
336+
337+
- **Properties:**
338+
- `value`: A read-only reactive value.
339+
- **Methods:**
340+
- `update(newValue | updater)`: Updates the signal's value.
341+
342+
### `computed(computation)`
343+
344+
Creates a computed value that automatically updates when its dependent signals change.
345+
346+
- **Parameter:**
347+
- `computation`: A function that returns a computed value based on one or more signals.
348+
349+
### `createEffect(effect)`
350+
351+
Creates an effect that runs after the component has mounted and whenever its dependent signals update.
352+
353+
- **Parameter:**
354+
- `effect`: A function that can optionally return a cleanup function.
355+
356+
### `cleanUp(cleanupFn)`
357+
358+
Registers a cleanup function to be executed when the component unmounts.
359+
360+
- **Parameter:**
361+
- `cleanupFn`: A function that performs cleanup operations.
362+
363+
### `createRef()`
364+
365+
Creates a reference object for DOM elements.
366+
367+
- **Property:**
368+
- `current`: Initially `null`, then set to the DOM element once rendered.
369+
370+
### `createPromise(asyncFunction)`
371+
372+
Wraps an asynchronous function into a promise handler that tracks its state.
373+
374+
- **Returns:**
375+
- A read-only signal with properties:
376+
- `data`: The resolved data or `null`.
377+
- `error`: The error object or `null`.
378+
- `status`: `"pending"`, `"resolved"`, or `"rejected"`.
379+
380+
### `lazy(loader)`
124381

125-
### `useState(initialValue)`
382+
Lazily loads a functional component.
126383

127-
A simple state management hook.
384+
- **Parameter:**
385+
- `loader`: A function that returns a promise resolving to a module with a default export (the component).
386+
- **Additional Props on the Lazy Component:**
387+
- `fallback`: JSX to render while loading.
388+
- `errorFallback`: A fallback UI or function to render if an error occurs.
128389

129390
## Contributing
130391

src/components/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createSignal } from "../../src/index.ts";
22
import ListsTest from "./ListsTest.tsx";
33
import PerformanceTest from "./Performance.tsx";
4+
import Users from "./Promises.tsx";
45
import StylesTest from "./StylesTest.tsx";
56
import Test from "./Test.tsx";
67
import TimerComponent from "./Timer.tsx";
@@ -16,7 +17,7 @@ const App = (props: any) => {
1617
<button onClick={() => visible.update((prev) => !prev)}>
1718
Show/Hide
1819
</button>
19-
{() => (visible.value ? <Test /> : "Hidden")}
20+
{() => (visible.value ? <Users /> : "Hidden")}
2021
</>
2122
);
2223
// return <StylesTest />;

0 commit comments

Comments
 (0)