chemical_docs/pages/api/EffectPage.tsx
2025-06-13 18:13:43 +02:00

120 lines
5 KiB
TypeScript

import React from 'react';
import { ContentPage } from '../../components/ContentPage';
import { InfoPanel } from '../../components/InfoPanel';
import { ApiSection } from '../../types';
const effectApi: ApiSection[] = [
{
title: 'Chemical.Effect',
description: 'Creates a side effect that runs after a batch of state changes has been processed and all dependent Computeds have been updated. Effects are used for interacting with the outside world, like updating UI, making network calls, or logging. They automatically re-run when their dependencies change.',
entries: [
{
signature: 'Chemical.Effect(effectFn: () => CleanUpFunction | ()): Effect',
description: 'Constructs a new Effect.',
parameters: [
{ name: 'effectFn', type: '() => CleanUpFunction | ()', description: 'A function that performs the side effect. Any reactive objects accessed via `:get()` inside this function become dependencies. This function can optionally return a `CleanUpFunction`.' },
],
returns: { type: 'Effect', description: 'A new Effect object.' },
notes: '`CleanUpFunction`: A function of type `() -> ()` that is called before the `effectFn` re-runs due to dependency changes, or when the Effect is destroyed.',
example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Effect = Chemical.Effect
local name = Value("User")
local counter = Value(0)
local loggingEffect = Effect(function()
-- This effect depends on 'name' and 'counter'
local currentName = name:get()
local currentCount = counter:get()
print("Effect triggered: Name is " .. currentName .. ", Count is " .. currentCount)
-- Optional cleanup function
return function()
print("Cleaning up effect for Name: " .. currentName .. ", Count: " .. currentCount)
end
end)
name:set("Admin") -- Effect re-runs (cleanup for "User", 0 runs first)
counter:set(5) -- Effect re-runs (cleanup for "Admin", 0 runs first)
-- Note: If both set calls happen in the same frame, the effect might only run once
-- with ("Admin", 5), after the cleanup for ("User", 0) or ("Admin",0) depending on intermediate states.
`,
},
],
},
{
title: 'Effect Methods',
entries: [
{
signature: 'effect:destroy()',
description: 'Destroys the Effect object. If the `effectFn` returned a cleanup function, it will be called. This also removes its dependencies on other reactive objects.',
example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Effect = Chemical.Effect
local isActive = Value(true)
local myEffect = Effect(function()
if isActive:get() then
print("Effect is active")
return function() print("Effect cleaning up: was active") end
else
print("Effect is inactive")
return function() print("Effect cleaning up: was inactive") end
end
end)
isActive:set(false) -- Effect re-runs
myEffect:destroy() -- The last cleanup function ("Effect cleaning up: was inactive") runs.
`,
},
{
signature: 'effect:clean()',
description: 'Explicitly runs the cleanup function returned by the last execution of `effectFn`, if one exists. This is typically managed internally by the scheduler or when the effect is destroyed, but can be called manually.',
example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Effect = Chemical.Effect
local data = Value("initial")
local effectWithCleanup = Effect(function()
local currentData = data:get()
print("Processing:", currentData)
return function() print("Cleaning up for:", currentData) end
end)
data:set("updated") -- Effect re-runs, cleanup for "initial" runs.
effectWithCleanup:clean() -- Cleanup for "updated" runs.
`,
notes: "This method is less commonly used directly. Destruction usually handles cleanup.",
},
],
},
];
export const EffectPage: React.FC = () => {
return (
<ContentPage title="Chemical.Effect" sections={effectApi}>
<InfoPanel type="note" title="Execution Timing & Batching">
<p>
Effects are batched and run by the Chemical scheduler. This typically happens at the
end of the current frame or scheduler tick, <strong>after</strong> all direct state changes
(e.g., from <code>:set()</code> on a Value) and <code>Computed</code> value updates for that tick
have been processed.
</p>
<p className="mt-2">
If an Effect's dependencies change multiple times within a single frame, the Effect
will only run <strong>once</strong>, reacting to the <strong>most recent (final) state</strong> of its
dependencies for that frame.
</p>
<p className="mt-2">
The <code>CleanUpFunction</code> (if returned by the <code>effectFn</code>) is called before the
<code>effectFn</code> re-runs due to dependency changes, or when the Effect is destroyed.
</p>
</InfoPanel>
</ContentPage>
);
};