diff --git a/langs/tr/api/api.md b/langs/tr/api/api.md new file mode 100644 index 00000000..2cc8d00e --- /dev/null +++ b/langs/tr/api/api.md @@ -0,0 +1,2388 @@ +# Basic Reactivity + +Solid's overall approach to reactivity is to wrap any reactive computation in +a function, and rerun that function when its dependencies update. +The Solid JSX compiler also wraps most JSX expressions (code in braces) with a +function, so they automatically update (and trigger corresponding DOM updates) +when their dependencies change. +More precisely, automatic rerunning of a function happens whenever the function +gets called in a _tracking scope_, such as a JSX expression +or API calls that build "computations" (`createEffect`, `createMemo`, etc.). +By default, the dependencies of a function get tracked automatically +when they're called in a tracking scope, by detecting when the function reads +reactive state (e.g., via a Signal getter or Store attribute). +As a result, you generally don't need to worry about dependencies yourselves. +(But if automatic dependency tracking ever doesn't produce the results you +want, you can [override dependency tracking](#reactive-utilities).) +This approach makes reactivity _composable_: calling one function +within another function generally causes the calling function +to inherit the dependencies of the called function. + +## `createSignal` + +```ts +import { createSignal } from "solid-js"; + +function createSignal( + initialValue: T, + options?: { equals?: false | ((prev: T, next: T) => boolean) } +): [get: () => T, set: (v: T) => T]; + +// available types for return value of createSignal: +import type { Signal, Accessor, Setter } from "solid-js"; +type Signal = [get: Accessor, set: Setter]; +type Accessor = () => T; +type Setter = (v: T | ((prev?: T) => T)) => T; +``` + +Signals are the most basic reactive primitive. They track a single value +(which can be any JavaScript object) that changes over time. +The Signal's value starts out equal to the passed first argument +`initialValue` (or `undefined` if there are no arguments). +The `createSignal` function returns a pair of functions as a two-element array: +a _getter_ (or _accessor_) and a _setter_. In typical use, you would +destructure this array into a named Signal like so: + +```js +const [count, setCount] = createSignal(0); +const [ready, setReady] = createSignal(false); +``` + +Calling the getter (e.g., `count()` or `ready()`) +returns the current value of the Signal. +Crucial to automatic dependency tracking, calling the getter +within a tracking scope causes the calling function to depend on this Signal, +so that function will rerun if the Signal gets updated. + +Calling the setter (e.g., `setCount(nextCount)` or `setReady(nextReady)`) +sets the Signal's value and _updates_ the Signal +(triggering dependents to rerun) +if the value actually changed (see details below). +As its only argument, the setter takes either the new value for the signal, +or a function that maps the last value of the signal to a new value. +The setter also returns the updated value. For example: + +```js +// read signal's current value, and +// depend on signal if in a tracking scope +// (but nonreactive outside of a tracking scope): +const currentCount = count(); + +// or wrap any computation with a function, +// and this function can be used in a tracking scope: +const doubledCount = () => 2 * count(); + +// or build a tracking scope and depend on signal: +const countDisplay =
{count()}
; + +// write signal by providing a value: +setReady(true); + +// write signal by providing a function setter: +const newCount = setCount((prev) => prev + 1); +``` + +> If you want to store a function in a Signal you must use the function form: +> +> ```js +> setValue(() => myFunction); +> ``` +> +> However, functions are not treated specially as the `initialValue` argument +> to `createSignal`, so you should pass a function initial value as is: +> +> ```js +> const [func, setFunc] = createSignal(myFunction); +> ``` + +##### Options + +Several primitives in Solid take an "options" object +as an optional last argument. +`createSignal`'s options object allows you to provide an +`equals` option. For example: + +```js +const [getValue, setValue] = createSignal(initialValue, { equals: false }); +``` + +By default, when calling a signal's setter, the signal only updates (and causes +dependents to rerun) if the new value is actually different than the old value, +according to JavaScript's `===` operator. + +Alternatively, you can set `equals` to `false` to always rerun dependents after +the setter is called, or you can pass your own function for testing equality. +Some examples: + +```js +// use { equals: false } to allow modifying object in-place; +// normally this wouldn't be seen as an update because the +// object has the same identity before and after change +const [object, setObject] = createSignal({ count: 0 }, { equals: false }); +setObject((current) => { + current.count += 1; + current.updated = new Date(); + return current; +}); + +// use { equals: false } signal as trigger without value: +const [depend, rerun] = createSignal(undefined, { equals: false }); +// now calling depend() in a tracking scope +// makes that scope rerun whenever rerun() gets called + +// define equality based on string length: +const [myString, setMyString] = createSignal("string", { + equals: (newVal, oldVal) => newVal.length === oldVal.length, +}); + +setMyString("strung"); // considered equal to the last value and won't cause updates +setMyString("stranger"); // considered different and will cause updates +``` + +## `createEffect` + +```ts +import { createEffect } from "solid-js"; + +function createEffect(fn: (v: T) => T, value?: T): void; +``` + +Effects are a general way to make arbitrary code ("side effects") +run whenever dependencies change, e.g., to modify the DOM manually. +`createEffect` creates a new computation that runs the given function +in a tracking scope, thus automatically tracking its dependencies, +and automatically reruns the function whenever the dependencies update. +For example: + +```js +const [a, setA] = createSignal(initialValue); + +// effect that depends on signal `a` +createEffect(() => doSideEffect(a())); +``` + +The effect function gets called with an argument equal to the value returned +from the effect function's last execution, or on the first call, +equal to the optional second argument to `createEffect`. +This allows you to compute diffs without creating an additional closure +to remember the last computed value. For example: + +```js +createEffect((prev) => { + const sum = a() + b(); + if (sum !== prev) console.log("sum changed to", sum); + return sum; +}, 0); +``` + +Effects are meant primarily for side effects that read but don't write +to the reactive system: +it's best to avoid setting signals in effects, which without care +can cause additional rendering or even infinite effect loops. +Instead, prefer using [`createMemo`](#creatememo) to compute new values +that depend on other reactive values, so the reactive system knows what +depends on what, and can optimize accordingly. + +The _first_ execution of the effect function is not immediate; +it's scheduled to run after the current rendering phase +(e.g., after calling the function passed to [`render`](#render), +[`createRoot`](#createroot), or [`runWithOwner`](#runwithowner)). +If you want to wait for the first execution to occur, use +[`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) +(which runs before the browser renders the DOM) or +`await Promise.resolve()` or `setTimeout(..., 0)` +(which run after browser rendering). + +```js +// assume this code is in a component function, so is part of a rendering phase +const [count, setCount] = createSignal(0); + +// this effect prints count at the beginning and when it changes +createEffect(() => console.log("count =", count())); +// effect won't run yet +console.log("hello"); +setCount(1); // effect still won't run yet +setCount(2); // effect still won't run yet + +queueMicrotask(() => { + // now `count = 2` will print + console.log("microtask"); + setCount(3); // immediately prints `count = 3` + console.log("goodbye"); +}); + +// --- overall output: --- +// hello +// count = 2 +// microtask +// count = 3 +// goodbye +``` + +This delay in first execution is useful because it means +an effect defined in a component scope runs after +the JSX returned by the component gets added the DOM. +In particular, [`ref`](#ref)s will already be set. +Thus you can use an effect to manipulate the DOM manually, +call vanilla JS libraries, or other side effects. + +Note that the first run of the effect still runs before the browser renders +the DOM to the screen (similar to React's `useLayoutEffect`). +If you need to wait until after rendering (e.g., to measure the rendering), +you can use `await Promise.resolve()` (or `Promise.resolve().then(...)`), +but note that subsequent use of reactive state (such as signals) +will not trigger the effect to rerun, as tracking is not +possible after an `async` function uses `await`. +Thus you should use all dependencies before the promise. + +If you'd rather an effect run immediately even for its first run, +use [`createRenderEffect`](#createrendereffect) or +[`createComputed`](#createcomputed). + +You can clean up your side effects in between executions of the effect function +by calling [`onCleanup`](#oncleanup) _inside_ the effect function. +Such a cleanup function gets called both in between effect executions and +when the effect gets disposed (e.g., the containing component unmounts). +For example: + +```js +// listen to event dynamically given by eventName signal +createEffect(() => { + const event = eventName(); + const callback = (e) => console.log(e); + ref.addEventListener(event, callback); + onCleanup(() => ref.removeEventListener(event, callback)); +}); +``` + +## `createMemo` + +```ts +import { createMemo } from "solid-js"; + +function createMemo( + fn: (v: T) => T, + value?: T, + options?: { equals?: false | ((prev: T, next: T) => boolean) } +): () => T; +``` + +Memos let you efficiently use a derived value in many reactive computations. +`createMemo` creates a readonly reactive value equal to the return value of +the given function and makes sure that function only gets executed when its dependencies change. + +```js +const value = createMemo(() => computeExpensiveValue(a(), b())); + +// read value +value(); +``` + +In Solid, you often don't need to wrap functions in memos; +you can alternatively just define and call a regular function +to get similar reactive behavior. +The main difference is when you call the function in multiple reactive settings. +In this case, when the function's dependencies update, the function will get +called multiple times unless it is wrapped in `createMemo`. For example: + +```js +const user = createMemo(() => searchForUser(username())); +// compare with: const user = () => searchForUser(username()); +return ( +
    +
  • Your name is "{user()?.name}"
  • +
  • + Your email is {user()?.email} +
  • +
+); +``` + +When the `username` signal updates, `searchForUser` will get called just once. +If the returned user actually changed, the `user` memo updates, and then both +list items will update automatically. + +If we had instead defined `user` as a plain function +`() => searchForUser(username())`, then `searchForUser` would have been +called twice, once when updating each list item. + +Another key difference is that a memo can shield dependents from updating +when the memo's dependencies change but the resulting memo value doesn't. +Like [`createSignal`](#createsignal), the derived signal made by `createMemo` +_updates_ (and triggers dependents to rerun) only when the value returned by +the memo function actually changes from the previous value, +according to JavaScript's `===` operator. +Alternatively, you can pass an options object with `equals` set to `false` +to always update the memo when its dependencies change, +or you can pass your own `equals` function for testing equality. + +The memo function gets called with an argument equal to the value returned +from the memo function's last execution, or on the first call, +equal to the optional second argument to `createMemo`. +This is useful for reducing computations, for example: + +```js +// track the sum of all values taken on by input() as it updates +const sum = createMemo((prev) => input() + prev, 0); +``` + +The memo function should not change other signals by calling setters +(it should be "pure"). +This enables Solid to optimize the execution order of memo updates +according to their dependency graph, so that all memos can update +at most once in response to a dependency change. + +## `createResource` + +```ts +import { createResource } from "solid-js"; +import type { ResourceReturn } from "solid-js"; + +type ResourceReturn = [ + { + (): T | undefined; + state: "unresolved" | "pending" | "ready" | "refreshing" | "errored" + loading: boolean; + error: any; + latest: T | undefined; + }, + { + mutate: (v: T | undefined) => T | undefined; + refetch: (info: unknown) => Promise | T; + } +]; + +export type ResourceOptions = { + initialValue?: T; + name?: string; + deferStream?: boolean; + ssrLoadFrom?: "initial" | "server"; + storage?: (init: T | undefined) => [Accessor, Setter]; + onHydrated?: (k: S | undefined, info: { value: T | undefined }) => void; +}; + +function createResource( + fetcher: ( + k: U, + info: { value: T | undefined; refetching: boolean | unknown } + ) => T | Promise, + options?: ResourceOptions +): ResourceReturn; + +function createResource( + source: U | false | null | (() => U | false | null), + fetcher: ( + k: U, + info: { value: T | undefined; refetching: boolean | unknown } + ) => T | Promise, + options?: ResourceOptions +): ResourceReturn; +``` + +Creates a signal that reflects the result of an async request. + +`createResource` takes an asynchronous fetcher function and returns a signal that is updated with the resulting data when the fetcher completes. + +There are two ways to use `createResource`: you can pass the fetcher function as the sole argument, or you can additionally pass a source signal as the first argument. The source signal will retrigger the fetcher whenever it changes, and its value will be passed to the fetcher. + +```js +const [data, { mutate, refetch }] = createResource(fetchData); +``` + +```js +const [data, { mutate, refetch }] = createResource(sourceSignal, fetchData); +``` + +In these snippets, the fetcher is the function `fetchData`, and `data()` is undefined until `fetchData` finishes resolving. In the first case, `fetchData` will be called immediately. +In the second, `fetchData` will be called as soon as `sourceSignal` has any value other than `false`, `null`, or `undefined`. +It will be called again whenever the value of `sourceSignal` changes, and that value will always be passed to `fetchData` as its first argument. + +You can call `mutate` to directly update the `data` signal (it works like any other signal setter). You can also call `refetch` to rerun the fetcher directly, and pass an optional argument to provide additional info to the fetcher: `refetch(info)`. + +`data` works like a normal signal getter: use `data()` to read the last returned value of `fetchData`. +But it also has extra reactive properties: `data.loading` tells you if the fetcher has been called but not returned, and `data.error` tells you if the request has errored out; if so, it contains the error thrown by the fetcher. (Note: if you anticipate errors, you may want to wrap `createResource` in an [ErrorBoundary](#).) + +As of **1.4.0**, `data.latest` will return the last returned value and won't trigger [Suspense](#) and [transitions](#usetransition); if no value has been returned yet, `data.latest` acts the same as `data()`. This can be useful if you want to show the out-of-date data while the new data is loading. + +`loading`, `error`, and `latest` are reactive getters and can be tracked. + +The `fetcher` is the async function that you provide to `createResource` to actually fetch the data. +It is passed two arguments: the value of the source signal (if provided), and an info object with two properties: `value` and `refetching`. `value` tells you the previously fetched value. +`refetching` is `true` if the fetcher was triggered using the `refetch` function and `false` otherwise. +If the `refetch` function was called with an argument (`refetch(info)`), `refetching` is set to that argument. + +```js +async function fetchData(source, { value, refetching }) { + // Fetch the data and return a value. + //`source` tells you the current value of the source signal; + //`value` tells you the last returned value of the fetcher; + //`refetching` is true when the fetcher is triggered by calling `refetch()`, + // or equal to the optional data passed: `refetch(info)` +} + +const [data, { mutate, refetch }] = createResource(getQuery, fetchData); + +// read value +data(); + +// check if loading +data.loading; + +// check if errored +data.error; + +// directly set value without creating promise +mutate(optimisticValue); + +// refetch the last request explicitly +refetch(); +``` + +**New in v1.4.0** + +If you're using `renderToStream`, you can tell Solid to wait for a resource before flushing the stream using the `deferStream` option: + +```js +// fetches a user and streams content as soon as possible +const [user] = createResource(() => params.id, fetchUser); + +// fetches a user but only streams content after this resource has loaded +const [user] = createResource(() => params.id, fetchUser, { + deferStream: true, +}); +``` + +**New in v1.5.0** + +We've added a new `state` field which covers a more detailed view of the Resource state beyond `loading` and `error`. You can now check whether a Resource is `"unresolved"`, `"pending"`, `"ready"`, `"refreshing"`, or `"error"`. + +| state | value resolved | loading | has error | +| ---------- | -------------- | ------- | --------- | +| unresolved | No | No | No | +| pending | No | Yes | No | +| ready | Yes | No | No | +| refreshing | Yes | Yes | No | +| errored | No | No | Yes | + +**New in v1.5.0** + +When server rendering resources especially when fetching when embedding Solid in other system that fetch before render, you might want to initiate the resource with this prefetched value instead of fetching again and having the resource serialize it isn't own state. You can use the new `ssrLoadFrom` option for this. Instead of using the default `"server"` value, you can pass `"initial"` and the resource will use `initialValue` as if it were the result of the first fetch for both SSR and hydration. + +**New in 1.5.0** *Experimental* + +Resources can be set with custom defined storage with the same signature as a Signal by using the `storage` option. For example using a custom reconciling store could be done this way: + +```ts +function createDeepSignal(value: T): Signal { + const [store, setStore] = createStore({ + value + }); + return [ + () => store.value, + (v: T) => { + const unwrapped = unwrap(store.value); + typeof v === "function" && (v = v(unwrapped)); + setStore("value", reconcile(v)); + return store.value; + } + ] as Signal; +} + +const [resource] = createResource(fetcher, { + storage: createDeepSignal +}); +``` + +# Lifecycles + +## `onMount` + +```ts +import { onMount } from "solid-js"; + +function onMount(fn: () => void): void; +``` + +Registers a method that runs after initial render and elements have been mounted. Ideal for using `ref`s and managing other one time side effects. It is equivalent to a `createEffect` which does not have any dependencies. + +## `onCleanup` + +```ts +import { onCleanup } from "solid-js"; + +function onCleanup(fn: () => void): void; +``` + +Registers a cleanup method that executes on disposal or recalculation of the current reactive scope. Can be used in any Component or Effect. + +## `onError` + +```ts +import { onError } from "solid-js"; + +function onError(fn: (err: any) => void): void; +``` + +Registers an error handler method that executes when child scope errors. Only the nearest scope error handlers execute. Rethrow to trigger up the line. + +# Reactive Utilities + +These helpers provide the ability to better schedule updates and control how reactivity is tracked. + +## `untrack` + +```ts +import { untrack } from "solid-js"; + +function untrack(fn: () => T): T; +``` + +Ignores tracking any of the dependencies in the executing code block and returns the value. + +## `batch` + +```ts +import { batch } from "solid-js"; + +function batch(fn: () => T): T; +``` + +Holds executing downstream computations within the block until the end to prevent unnecessary recalculation. [Solid Store](#createstore)'s set method, [Mutable Store](#createmutable)'s array methods, and Effects automatically wrap their code in a batch. + +## `on` + +```ts +import { on } from "solid-js"; + +function on any> | (() => any), U>( + deps: T, + fn: (input: T, prevInput: T, prevValue?: U) => U, + options: { defer?: boolean } = {} +): (prevValue?: U) => U | undefined; +``` + +`on` is designed to be passed into a computation to make its dependencies explicit. If an array of dependencies is passed, `input` and `prevInput` are arrays. + +```js +createEffect(on(a, (v) => console.log(v, b()))); + +// is equivalent to: +createEffect(() => { + const v = a(); + untrack(() => console.log(v, b())); +}); +``` + +You can also not run the computation immediately and instead opt in for it to only run on change by setting the defer option to true. + +```js +// doesn't run immediately +createEffect(on(a, (v) => console.log(v), { defer: true })); + +setA("new"); // now it runs +``` + +Please note that on `stores` and `mutable`, adding or removing a property from the parent object will trigger an effect. See [`createMutable`](#createMutable) + +## `createRoot` + +```ts +import { createRoot } from "solid-js"; + +function createRoot(fn: (dispose: () => void) => T): T; +``` + +Creates a new non-tracked owner scope that doesn't auto-dispose. This is useful for nested reactive scopes that you do not wish to release when the parent re-evaluates. + +All Solid code should be wrapped in one of these top level as they ensure that all memory/computations are freed up. Normally you do not need to worry about this as `createRoot` is embedded into all `render` entry functions. + +## `getOwner` + +```ts +import { getOwner } from "solid-js"; + +function getOwner(): Owner; +``` + +Gets the reactive scope that owns the currently running code, e.g., +for passing into a later call to `runWithOwner` outside of the current scope. + +Internally, computations (effects, memos, etc.) create owners which are +children of their owner, all the way up to the root owner created by +`createRoot` or `render`. In particular, this ownership tree lets Solid +automatically clean up a disposed computation by traversing its subtree +and calling all [`onCleanup`](#oncleanup) callbacks. +For example, when a `createEffect`'s dependencies change, the effect calls +all descendant `onCleanup` callbacks before running the effect function again. +Calling `getOwner` returns the current owner node that is responsible +for disposal of the current execution block. + +Components are not computations, so do not create an owner node, but they are +typically rendered from a `createEffect` which does, so the result is similar: +when a component gets unmounted, all descendant `onCleanup` callbacks get +called. Calling `getOwner` from a component scope returns the owner that is +responsible for rendering and unmounting that component. + +Note that the owning reactive scope isn't necessarily _tracking_. +For example, [`untrack`](#untrack) turns off tracking for the duration +of a function (without creating a new reactive scope), as do +components created via JSX (``). + +## `runWithOwner` + +```ts +import { runWithOwner } from 'solid-js'; + +function runWithOwner(owner: Owner, fn: (() => void) => T): T; +``` + +Executes the given function under the provided owner, +instead of (and without affecting) the owner of the outer scope. +By default, computations created by `createEffect`, `createMemo`, etc. +are owned by the owner of the currently executing code (the return value of +`getOwner`), so in particular will get disposed when their owner does. +Calling `runWithOwner` provides a way to override this default to a manually +specified owner (typically, the return value from a previous call to +`getOwner`), enabling more precise control of when computations get disposed. + +Having a (correct) owner is important for two reasons: + +- Computations without an owner cannot be cleaned up. For example, if you call + `createEffect` without an owner (e.g., in the global scope), the effect will + continue running forever, instead of being disposed when its owner gets + disposed. +- [`useContext`](#usecontext) obtains context by walking up the owner tree + to find the nearest ancestor providing the desired context. + So without an owner you cannot look up any provided context + (and with the wrong owner, you might obtain the wrong context). + +Manually setting the owner is especially helpful when doing reactivity outside +of any owner scope. In particular, asynchronous computation +(via either `async` functions or callbacks like `setTimeout`) +lose the automatically set owner, so remembering the original owner via +`getOwner` and restoring it via `runWithOwner` is necessary in these cases. +For example: + +```js +const owner = getOwner(); +setTimeout(() => { + // This callback gets run without owner. + // Restore owner via runWithOwner: + runWithOwner(owner, () => { + const foo = useContext(FooContext); + createEffect(() => { + console.log(foo); + }); + }); +}, 1000); +``` + +Note that owners are not what determines dependency tracking, +so `runWithOwner` does not help with tracking in asynchronous functions; +use of reactive state in the asynchronous part (e.g. after the first `await`) +will not be tracked as a dependency. + +## `mergeProps` + +```ts +import { mergeProps } from "solid-js"; + +function mergeProps(...sources: any): any; +``` + +A reactive object `merge` method. Useful for setting default props for components in case caller doesn't provide them. Or cloning the props object including reactive properties. + +This method works by using a proxy and resolving properties in reverse order. This allows for dynamic tracking of properties that aren't present when the prop object is first merged. + +```js +// default props +props = mergeProps({ name: "Smith" }, props); + +// clone props +newProps = mergeProps(props); + +// merge props +props = mergeProps(props, otherProps); +``` + +## `splitProps` + +```ts +import { splitProps } from "solid-js"; + +function splitProps( + props: T, + ...keys: Array<(keyof T)[]> +): [...parts: Partial]; +``` + +Splits a reactive object by keys. + +It takes a reactive object and any number of arrays of keys; for each array of keys, it will return a reactive object with just those properties of the original object. The last reactive object in the returned array will have any leftover properties of the original object. + +This can be useful if you want to consume a subset of props and pass the rest to a child. + +```js +function MyComponent(props) { + const [local, others] = splitProps(props, ["children"]); + + return ( + <> +
{local.children}
+ + + ); +} +``` + +Because `splitProps` takes any number of arrays, we can split a props object +as much as we wish (if, for example, we had multiple child components that +each required a subset of the props). + +Let's say a component was passed six props: + +```js +; +function MyComponent(props) { + console.log(props); // {a: 1, b: 2, c: 3, d: 4, e: 5, foo: "bar"} + const [vowels, consonants, leftovers] = splitProps( + props, + ["a", "e"], + ["b", "c", "d"] + ); + console.log(vowels); // {a: 1, e: 5} + console.log(consonants); // {b: 2, c: 3, d: 4} + console.log(leftovers.foo); // bar +} +``` + +## `useTransition` + +```ts +import { useTransition } from "solid-js"; + +function useTransition(): [ + pending: () => boolean, + startTransition: (fn: () => void) => Promise +]; +``` + +Used to batch async updates in a transaction deferring commit until all async processes are complete. This is tied into Suspense and only tracks resources read under Suspense boundaries. + +```js +const [isPending, start] = useTransition(); + +// check if transitioning +isPending(); + +// wrap in transition +start(() => setSignal(newValue), () => /* transition is done */) +``` + +## `startTransition` + +**New in v1.1.0** + +```ts +import { startTransition } from 'solid-js'; + +function startTransition: (fn: () => void) => Promise; +``` + +Similar to `useTransition` except there is no associated pending state. This one can just be used directly to start the Transition. + +## `observable` + +```ts +import { observable } from "solid-js"; + +function observable(input: () => T): Observable; +``` + +This method takes a signal and produces an Observable. +You can consume it from another Observable library of your choice, typically +with the `from` operator. + +```js +// How to integrate rxjs with a solid.js signal +import { observable } from "solid-js"; +import { from } from "rxjs"; + +const [s, set] = createSignal(0); + +const obsv$ = from(observable(s)); + +obsv$.subscribe((v) => console.log(v)); +``` + +You can also use `from` without `rxjs`; see below. + +## `from` + +**New in v1.1.0** + +```ts +import { from } from "solid-js"; + +function from( + producer: + | ((setter: (v: T) => T) => () => void) + | { + subscribe: ( + fn: (v: T) => void + ) => (() => void) | { unsubscribe: () => void }; + } +): () => T; +``` + +A helper to make it easier to interop with external producers like RxJS observables or with Svelte Stores. This basically turns any subscribable (object with a `subscribe` method) into a Signal and manages subscription and disposal. + +```js +const signal = from(obsv$); +``` + +It can also take a custom producer function where the function is passed a setter function returns a unsubscribe function: + +```js +const clock = from((set) => { + const t = setInterval(() => set(1), 1000); + return () => clearInterval(t); +}); +``` + +> Note: Signals created by `from` have equality checks turned off to interface better with external streams and sources. + +## `mapArray` + +```ts +import { mapArray } from "solid-js"; + +function mapArray( + list: () => readonly T[], + mapFn: (v: T, i: () => number) => U +): () => U[]; +``` + +Reactive map helper that caches each item by reference to reduce unnecessary mapping on updates. It only runs the mapping function once per value and then moves or removes it as needed. The index argument is a signal. The map function itself is not tracking. + +Underlying helper for the `` control flow. + +```js +const mapped = mapArray(source, (model) => { + const [name, setName] = createSignal(model.name); + const [description, setDescription] = createSignal(model.description); + + return { + id: model.id, + get name() { + return name(); + }, + get description() { + return description(); + }, + setName, + setDescription, + }; +}); +``` + +## `indexArray` + +```ts +import { indexArray } from "solid-js"; + +function indexArray( + list: () => readonly T[], + mapFn: (v: () => T, i: number) => U +): () => U[]; +``` + +Similar to `mapArray` except it maps by index. The item is a signal and the index is now the constant. + +Underlying helper for the `` control flow. + +```js +const mapped = indexArray(source, (model) => { + return { + get id() { + return model().id + } + get firstInitial() { + return model().firstName[0]; + }, + get fullName() { + return `${model().firstName} ${model().lastName}`; + }, + } +}); +``` + +# Stores + +These APIs are available at `solid-js/store`. They allow the creation of stores: [proxy objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) that allow a tree of signals to be independently tracked and modified. + +## Using Stores + +### `createStore` + +```ts +import { createStore } from "solid-js/store"; +import type { StoreNode, Store, SetStoreFunction } from "solid-js/store"; + +function createStore( + state: T | Store +): [get: Store, set: SetStoreFunction]; +type Store = T; // conceptually readonly, but not typed as such +``` + +The create function takes an initial state, wraps it in a store, and returns a readonly proxy object and a setter function. + +```js +const [state, setState] = createStore(initialValue); + +// read value +state.someValue; + +// set value +setState({ merge: "thisValue" }); + +setState("path", "to", "value", newValue); +``` + +As proxies, store objects only track when a property is accessed. + +When nested objects are accessed, stores will produce nested store objects, and this applies all the way down the tree. However, this only applies to arrays and plain objects. Classes are not wrapped, so objects like `Date`, `HTMLElement`, `RegExp`, `Map`, `Set` won't be granularly reactive as properties on a store. + +#### Arrays in stores + +As of version **1.4.0**, the top level state object can be an array. In prior versions, create an object to wrap the array: + +```jsx +//After Solid 1.4.0 +const [todos, setTodos] = createStore([ + { id: 1, title: "Thing I have to do", done: false }, + { id: 2, title: "Learn a New Framework", done: false }, +]); +... +{todo => }; +``` + +```jsx +//Before 1.4.0 +const [state, setState] = createStore({ + todos: [ + { id: 1, title: "Thing I have to do", done: false }, + { id: 2, title: "Learn a New Framework", done: false }, + ], +}); +{(todo) => }; +``` + +Note that modifying an array inside a store will not trigger computations that subscribe to the array directly. For example: + +```js +createEffect(() => { + console.log(state.todos); +}); + +//This will not trigger the effect: +setState(todos, state.todos.length, { id: 3 }); +//This will trigger the effect, because the array reference changes: +setState("todos", (prev) => [...prev, { id: 3 }]); +``` + +### Getters + +Store objects support the use of getters to store calculated values. + +```js +const [state, setState] = createStore({ + user: { + firstName: "John", + lastName: "Smith", + get fullName() { + return `${this.firstName} ${this.lastName}`; + }, + }, +}); +``` + +These are getters that rerun when accessed, +so you still need to use a memo if you want to cache a value: + +```js +let fullName; +const [state, setState] = createStore({ + user: { + firstName: "John", + lastName: "Smith", + get fullName() { + return fullName(); + }, + }, +}); +fullName = createMemo(() => `${state.user.firstName} ${state.user.lastName}`); +``` + +### Updating Stores + +Changes can take the form of function that passes previous state and returns new state or a value. Objects are always shallowly merged. Set values to `undefined` to delete them from the Store. + +```js +const [state, setState] = createStore({ + firstName: "John", + lastName: "Miller", +}); + +setState({ firstName: "Johnny", middleName: "Lee" }); +// ({ firstName: 'Johnny', middleName: 'Lee', lastName: 'Miller' }) + +setState((state) => ({ preferredName: state.firstName, lastName: "Milner" })); +// ({ firstName: 'Johnny', preferredName: 'Johnny', middleName: 'Lee', lastName: 'Milner' }) +``` + +It supports paths including key arrays, object ranges, and filter functions. + +setState also supports nested setting where you can indicate the path to the change. When nested the state you are updating may be other non Object values. Objects are still merged but other values (including Arrays) are replaced. + +```js +const [state, setState] = createStore({ + counter: 2, + list: [ + { id: 23, title: 'Birds' } + { id: 27, title: 'Fish' } + ] +}); + +setState('counter', c => c + 1); +setState('list', l => [...l, {id: 43, title: 'Marsupials'}]); +setState('list', 2, 'read', true); +// { +// counter: 3, +// list: [ +// { id: 23, title: 'Birds' } +// { id: 27, title: 'Fish' } +// { id: 43, title: 'Marsupials', read: true } +// ] +// } +``` + +Path can be string keys, array of keys, iterating objects ({from, to, by}), or filter functions. This gives incredible expressive power to describe state changes. + +```js +const [state, setState] = createStore({ + todos: [ + { task: 'Finish work', completed: false } + { task: 'Go grocery shopping', completed: false } + { task: 'Make dinner', completed: false } + ] +}); + +setState('todos', [0, 2], 'completed', true); +// { +// todos: [ +// { task: 'Finish work', completed: true } +// { task: 'Go grocery shopping', completed: false } +// { task: 'Make dinner', completed: true } +// ] +// } + +setState('todos', { from: 0, to: 1 }, 'completed', c => !c); +// { +// todos: [ +// { task: 'Finish work', completed: false } +// { task: 'Go grocery shopping', completed: true } +// { task: 'Make dinner', completed: true } +// ] +// } + +setState('todos', todo => todo.completed, 'task', t => t + '!') +// { +// todos: [ +// { task: 'Finish work', completed: false } +// { task: 'Go grocery shopping!', completed: true } +// { task: 'Make dinner!', completed: true } +// ] +// } + +setState('todos', {}, todo => ({ marked: true, completed: !todo.completed })) +// { +// todos: [ +// { task: 'Finish work', completed: true, marked: true } +// { task: 'Go grocery shopping!', completed: false, marked: true } +// { task: 'Make dinner!', completed: false, marked: true } +// ] +// } +``` + +## Store Utilities + +### `produce` + +```ts +import { produce } from "solid-js/store"; + +function produce( + fn: (state: T) => void +): ( + state: T extends NotWrappable ? T : Store +) => T extends NotWrappable ? T : Store; +``` + +Immer inspired API for Solid's Store objects that allows for localized mutation. + +```js +setState( + produce((s) => { + s.user.name = "Frank"; + s.list.push("Pencil Crayon"); + }) +); +``` + +### `reconcile` + +```ts +import { reconcile } from "solid-js/store"; + +function reconcile( + value: T | Store, + options?: { + key?: string | null; + merge?: boolean; + } = { key: "id" } +): ( + state: T extends NotWrappable ? T : Store +) => T extends NotWrappable ? T : Store; +``` + +Diffs data changes when we can't apply granular updates. Useful for when dealing with immutable data from stores or large API responses. + +The key is used when available to match items. By default `merge` false does referential checks where possible to determine equality and replaces where items are not referentially equal. `merge` true pushes all diffing to the leaves and effectively morphs the previous data to the new value. + +```js +// subscribing to an observable +const unsubscribe = store.subscribe(({ todos }) => ( + setState('todos', reconcile(todos))); +); +onCleanup(() => unsubscribe()); +``` + +### `unwrap` + +```ts +import { unwrap } from "solid-js/store"; + +function unwrap(store: Store): T; +``` + +Returns the underlying data in the store without a proxy. + +### `createMutable` + +```ts +import { createMutable } from 'solid-js/store'; + +function createMutable( + state: T | Store, +): Store; +``` + +Creates a new mutable Store proxy object. Stores only trigger updates on values changing. Tracking is done by intercepting property access and automatically tracks deep nesting via proxy. + +Useful for integrating external systems or as a compatibility layer with MobX/Vue. + +> **Note:** A mutable state can be passed around and mutated anywhere, which can make it harder to follow and easier to break unidirectional flow. It is generally recommended to use `createStore` instead. The `produce` modifier can give many of the same benefits without any of the downsides. + +```js +const state = createMutable(initialValue); + +// read value +state.someValue; + +// set value +state.someValue = 5; + +state.list.push(anotherValue); +``` + +Mutables support setters along with getters. + +```js +const user = createMutable({ + firstName: "John", + lastName: "Smith", + get fullName() { + return `${this.firstName} ${this.lastName}`; + }, + set fullName(value) { + [this.firstName, this.lastName] = value.split(" "); + }, +}); +``` + +### `modifyMutable` + +**New in v1.4.0** + +```ts +import { modifyMutable } from 'solid-js/store'; + +function modifyMutable(mutable: T, modifier: (state: T) => T): void; +``` + +This helper function simplifies making multiple changes to a mutable Store +(as returned by [`createMutable`](#createmutable)) +in a single [`batch`](#batch), +so that dependant computations update just once instead of once per update. +The first argument is the mutable Store to modify, +and the second argument is a Store modifier such as those returned by +[`reconcile`](#reconcile) or [`produce`](#produce). +(If you pass in your own modifier function, beware that its argument is +an unwrapped version of the Store.) + +For example, suppose we have a UI depending on multiple fields of a mutable: + +```tsx +const state = createMutable({ + user: { + firstName: "John", + lastName: "Smith", + }, +}); + +

Hello {state.user.firstName + ' ' + state.user.lastName}

+``` + +Modifying *n* fields in sequence will cause the UI to update *n* times: + +```ts +state.user.firstName = "Jake"; // triggers update +state.user.lastName = "Johnson"; // triggers another update +``` + +To trigger just a single update, we could modify the fields in a `batch`: + +```ts +batch(() => { + state.user.firstName = "Jake"; + state.user.lastName = "Johnson"; +}); +``` + +`modifyMutable` combined with `reconcile` or `produce` +provides two alternate ways to do similar things: + +```ts +// Replace state.user with the specified object (deleting any other fields) +modifyMutable(state.user, reconcile({ + firstName: "Jake", + lastName: "Johnson", +}); + +// Modify two fields in batch, triggering just one update +modifyMutable(state.user, produce((u) => { + u.firstName = "Jake"; + u.lastName = "Johnson"; +}); +``` + +# Component APIs + +## `createContext` + +```ts +import { createContext } from "solid-js"; +import type { Context } from "solid-js"; + +interface Context { + id: symbol; + Provider: (props: { value: T; children: any }) => any; + defaultValue: T; +} + +function createContext(defaultValue?: T): Context; +``` + +Context provides a form of dependency injection in Solid. It is used to save from needing to pass data as props through intermediate components. + +This function creates a new context object that can be used with `useContext` and provides the `Provider` control flow. Default Context is used when no `Provider` is found above in the hierarchy. + +```js +export const CounterContext = createContext([{ count: 0 }, {}]); + +export function CounterProvider(props) { + const [state, setState] = createStore({ count: props.count || 0 }); + const counter = [ + state, + { + increment() { + setState("count", (c) => c + 1); + }, + decrement() { + setState("count", (c) => c - 1); + }, + }, + ]; + + return ( + + {props.children} + + ); +} +``` + +The value passed to provider is passed to `useContext` as is. That means wrapping as a reactive expression will not work. You should pass in Signals and Stores directly instead of accessing them in the JSX. + +## `useContext` + +```ts +import { useContext } from "solid-js"; + +function useContext(context: Context): T; +``` + +Used to grab context to allow for deep passing of props without having to pass them through each Component function. + +```js +const [state, { increment, decrement }] = useContext(CounterContext); +``` + +## `children` + +```ts +import { children } from "solid-js"; +import type { JSX, ResolvedChildren } from "solid-js"; + +function children(fn: () => JSX.Element): () => ResolvedChildren; +``` + +The `children` helper is for complicated interactions with `props.children`, +when you're not just passing children on to another component +using `{props.children}` once in JSX. +Normally you pass in a getter for `props.children` like so: + +```js +const resolved = children(() => props.children); +``` + +The return value is a [memo](#creatememo) evaluating to the resolved children, +which updates whenever the children change. +Using this memo instead of accessing `props.children` directly +has some important advantages in some scenarios. +The underlying issue is that, when you specify component children via JSX, +Solid automatically defines `props.children` as a property getter, +so that the children are created (in particular, DOM is created) +whenever `props.children` gets accessed. Two particular consequences: + +- If you access `props.children` multiple times, the children + (and associated DOM) get created multiple times. + This is useful if you want the DOM to be duplicated (as DOM nodes can appear + in only one parent element), but in many cases it creates redundant DOM nodes. + If you instead call `resolved()` multiple times, you re-use the same children. +- If you access `props.children` outside of a tracking scope (e.g., in an + event handler), then you create children that will never be cleaned up. + If you instead call `resolved()`, you re-use the already resolved children. + You also guarantee that the children are tracked in the current component, + as opposed to another tracking scope such as another component. + +In addition, the `children` helper "resolves" children by +calling argumentless functions and flattening arrays of arrays into an array. +For example, a child specified with JSX like `{signal() * 2}` gets wrapped into +a getter function `() => count() * 2` in `props.children`, but gets evaluated +to an actual number in `resolved`, properly depending on a `count` signal. + +If the given `props.children` is not an array +(which occurs when the JSX tag has a single child), +then the `children` helper will not normalize it into an array. +This is useful behavior e.g. when the intention is to pass a single function +as a child, which can be detected via `typeof resolved() === 'function'`. +If you want to normalize to an array, the returned memo has a `toArray` method(*new in 1.5*). + +Here is an example of automatically setting the `class` attribute of any +child that resolves to an `Element`, in addition to rendering the children: + +```tsx +const resolved = children(() => props.children); + +createEffect(() => { + let list = resolved.toArray(); + for (let child of list) child?.setAttribute?.("class", myClass()); +}); + +return
{resolved()}
; +``` + +(Note that this approach is not particularly recommended: +it is usually better to follow a declarative approach of passing +in the desired class via props or context to the children components.) + +On the other hand, you don't need (and in some cases, don't want) +to use the `children` helper if you're just passing `props.children` +on to another component or element via JSX: + +```tsx +const Wrapper = (props) => { + return
{props.children}
; +}; +``` + +An important aspect of the `children` helper is that it forces the children +to be created and resolved, as it accesses `props.children` immediately. +This can be undesirable for conditional rendering, +e.g., when using the children within a [``](#) component. +For example, the following code always evaluates the children: + +```tsx +const resolved = children(() => props.children); + +return {resolved()}; +``` + +To evaluate the children only when `` would render them, you can +push the call to `children` inside a component or a function within ``, +which only evaluates its children when the `when` condition is true. +Another nice workaround is to pass `props.children` to the `children` helper +only when you actually want to evaluate the children: + +```ts +const resolved = children(() => visible() && props.children); +``` + +## `lazy` + +```ts +import { lazy } from "solid-js"; + +function lazy>( + fn: () => Promise<{ default: T }> +): T & { preload: () => Promise }; +``` + +Used to lazy load components to allow for code splitting. Components are not loaded until rendered. Lazy loaded components can be used the same as its statically imported counterpart, receiving props etc... Lazy components trigger `` + +```js +// wrap import +const ComponentA = lazy(() => import("./ComponentA")); + +// use in JSX +; +``` + +## `createUniqueId` + +```ts +import { createUniqueId } from "solid-js"; + +function createUniqueId(): string; +``` + +A universal id generator that is stable across server/browser. + +```js +const id = createUniqueId(); +``` + +> **Note** on the server this only works under hydratable components + +# Secondary Primitives + +You probably won't need them for your first app, but these are useful tools to have. + +## `createDeferred` + +```ts +import { createDeferred } from "solid-js"; + +function createDeferred( + source: () => T, + options?: { + timeoutMs?: number; + equals?: false | ((prev: T, next: T) => boolean); + } +): () => T; +``` + +Creates a readonly that only notifies downstream changes when the browser is idle. `timeoutMs` is the maximum time to wait before forcing the update. + +## `createRenderEffect` + +```ts +import { createRenderEffect } from "solid-js"; + +function createRenderEffect(fn: (v: T) => T, value?: T): void; +``` + +A render effect is a computation similar to a regular effect +(as created by [`createEffect`](#createeffect)), +but differs in when Solid schedules the first execution of the effect function. +While `createEffect` waits for the current rendering phase to be complete, +`createRenderEffect` immediately calls the function. +Thus the effect runs as DOM elements are being created and updated, +but possibly before specific elements of interest have been created, +and probably before those elements have been connected to the document. +In particular, [`ref`](#ref)s will not be set before the initial effect call. +Indeed, Solid uses `createRenderEffect` to implement the rendering phase +itself, including setting of `ref`s. + +Reactive updates to render effects are identical to effects: they queue up in +response to a reactive change (e.g., a single signal update, or a `batch` of +changes, or collective changes during an entire render phase) and run in a +single [`batch`](#batch) afterward (together with effects). +In particular, all signal updates within a render effect are batched. + +Here is an example of the behavior. +(Compare with the example in [`createEffect`](#createeffect).) + +```js +// assume this code is in a component function, so is part of a rendering phase +const [count, setCount] = createSignal(0); + +// this effect prints count at the beginning and when it changes +createRenderEffect(() => console.log("count =", count())); +// render effect runs immediately, printing `count = 0` +console.log("hello"); +setCount(1); // effect won't run yet +setCount(2); // effect won't run yet + +queueMicrotask(() => { + // now `count = 2` will print + console.log("microtask"); + setCount(3); // immediately prints `count = 3` + console.log("goodbye"); +}); + +// --- overall output: --- +// count = 0 [this is the only added line compared to createEffect] +// hello +// count = 2 +// microtask +// count = 3 +// goodbye +``` + +Just like `createEffect`, the effect function gets called with an argument +equal to the value returned from the effect function's last execution, +or on the first call, equal to the optional second argument to +`createRenderEffect`. + +## `createComputed` + +```ts +import { createComputed } from "solid-js"; + +function createComputed(fn: (v: T) => T, value?: T): void; +``` + +`createComputed` creates a new computation that immediately runs the given +function in a tracking scope, thus automatically tracking its dependencies, +and automatically reruns the function whenever the dependencies changes. +The function gets called with an argument equal to the value returned +from the function's last execution, or on the first call, +equal to the optional second argument to `createComputed`. +Note that the return value of the function is not otherwise exposed; +in particular, `createComputed` has no return value. + +`createComputed` is the most immediate form of reactivity in Solid, and is +most useful for building other reactive primitives. +(For example, some other Solid primitives are built from `createComputed`.) +But it should be used with care, as `createComputed` can easily cause more +unnecessary updates than other reactive primitives. +Before using it, consider the closely related primitives +[`createMemo`](#creatememo) and [`createRenderEffect`](#createrendereffect). + +Like `createMemo`, `createComputed` calls its function immediately on updates +(unless you're in a [batch](#batch), [effect](#createEffect), or +[transition](#use-transition)). +However, while `createMemo` functions should be pure (not set any signals), +`createComputed` functions can set signals. +Related, `createMemo` offers a readonly signal for the return value of the +function, whereas to do the same with `createComputed` you would need to +set a signal within the function. +If it is possible to use pure functions and `createMemo`, this is likely +more efficient, as Solid optimizes the execution order of memo updates, +whereas updating a signal within `createComputed` will immediately trigger +reactive updates some of which may turn out to be unnecessary. + +Like `createRenderEffect`, `createComputed` calls its function for the first +time immediately. But they differ in how updates are performed. +While `createComputed` generally updates immediately, `createRenderEffect` +updates queue to run (along with `createEffect`s) +after the current render phase. +Thus `createRenderEffect` can perform fewer overall updates, +but is slightly less immediate. + +## `createReaction` + +**New in v1.3.0** + +```ts +import { createReaction } from "solid-js"; + +function createReaction(onInvalidate: () => void): (fn: () => void) => void; +``` + +Sometimes it is useful to separate tracking from re-execution. This primitive registers a side effect that is run the first time the expression wrapped by the returned tracking function is notified of a change. + +```js +const [s, set] = createSignal("start"); + +const track = createReaction(() => console.log("something")); + +// next time s changes run the reaction +track(() => s()); + +set("end"); // "something" + +set("final"); // no-op as reaction only runs on first update, need to call track again. +``` + +## `createSelector` + +```ts +import { createSelector } from "solid-js"; + +function createSelector( + source: () => T, + fn?: (a: U, b: T) => boolean +): (k: U) => boolean; +``` + +Creates a conditional signal that only notifies subscribers when entering or exiting their key matching the value. Useful for delegated selection state. As it makes the operation O(1) instead of O(n). + +```js +const isSelected = createSelector(selectedId); + + + {(item) =>
  • {item.name}
  • } +
    ; +``` + +# Rendering + +These imports are exposed from `solid-js/web`. + +## `render` + +```ts +import { render } from "solid-js/web"; +import type { JSX, MountableElement } from "solid-js/web"; + +function render(code: () => JSX.Element, element: MountableElement): () => void; +``` + +This is the browser app entry point. +Provide a top-level component function and an element to mount to. +It is recommended this element be empty: +while `render` will just append children, +the returned `dispose` function will remove all children. + +```js +const dispose = render(App, document.getElementById("app")); +// or +const dispose = render(() => , document.getElementById("app")); +``` + +It's important that the first argument is a function: do not pass JSX directly +(as in `render(, ...)`), because this will call `App` before `render` can +set up a root to track signal dependencies within `App`. + +## `hydrate` + +```ts +import { hydrate } from "solid-js/web"; + +function hydrate(fn: () => JSX.Element, node: MountableElement): () => void; +``` + +This method is similar to `render` except it attempts to rehydrate what is already rendered to the DOM. When initializing in the browser a page has already been server rendered. + +```js +const dispose = hydrate(App, document.getElementById("app")); +``` + +## `renderToString` + +```ts +import { renderToString } from "solid-js/web"; + +function renderToString( + fn: () => T, + options?: { + nonce?: string; + renderId?: string; + } +): string; +``` + +Renders to a string synchronously. The function also generates a script tag for progressive hydration. Options include eventNames to listen to before the page loads and play back on hydration, and nonce to put on the script tag. + +`renderId` is used to namespace renders when having multiple top level roots. + +```js +const html = renderToString(App); +``` + +## `renderToStringAsync` + +```ts +import { renderToStringAsync } from "solid-js/web"; + +function renderToStringAsync( + fn: () => T, + options?: { + timeoutMs?: number; + renderId?: string; + nonce?: string; + } +): Promise; +``` + +Same as `renderToString` except it will wait for all `` boundaries to resolve before returning the results. Resource data is automatically serialized into the script tag and will be hydrated on client load. + +`renderId` is used to namespace renders when having multiple top level roots. + +```js +const html = await renderToStringAsync(App); +``` + +## `renderToStream` + +**New in v1.3.0** + +```ts +import { renderToStream } from "solid-js/web"; + +function renderToStream( + fn: () => T, + options?: { + nonce?: string; + renderId?: string; + onCompleteShell?: () => void; + onCompleteAll?: () => void; + } +): { + pipe: (writable: { write: (v: string) => void }) => void; + pipeTo: (writable: WritableStream) => void; +}; +``` + +This method renders to a stream. It renders the content synchronously including any Suspense fallback placeholders, and then continues to stream the data and HTML from any async resource as it completes. + +```js +// node +renderToStream(App).pipe(res); + +// web stream +const { readable, writable } = new TransformStream(); +renderToStream(App).pipeTo(writable); +``` + +`onCompleteShell` fires when synchronous rendering is complete before writing the first flush to the stream out to the browser. `onCompleteAll` is called when all server Suspense boundaries have settled. `renderId` is used to namespace renders when having multiple top level roots. + +> Note this API replaces the previous `pipeToWritable` and `pipeToNodeWritable` APIs. + +## `isServer` + +```ts +import { isServer } from "solid-js/web"; + +const isServer: boolean; +``` + +This indicates that the code is being run as the server or browser bundle. As the underlying runtimes export this as a constant boolean it allows bundlers to eliminate the code and their used imports from the respective bundles. + +```js +if (isServer) { + // I will never make it to the browser bundle +} else { + // won't be run on the server; +} +``` + +## `DEV` + +```ts +import { DEV } from "solid-js"; + +const DEV: object | undefined; +``` + +On the client, Solid provides +(via [conditional exports](https://nodejs.org/api/packages.html#conditional-exports)) +different builds depending on whether the `development` condition is set. +Development mode provides some additional checking — e.g. detecting accidental +use of multiple instances of Solid — which are removed in production builds. + +If you want code to run only in development mode (most useful in libraries), +you can check whether the `DEV` export is defined. Note that it is always +defined on the server, so you may want to combine with [`isServer`](#isserver): + +```ts +import { DEV } from "solid-js"; +import { isServer } from "solid-js/web"; + +if (DEV && !isServer) { + console.log(...); +} +``` + +## `HydrationScript` + +```ts +import { generateHydrationScript, HydrationScript } from "solid-js/web"; + +function generateHydrationScript(options: { + nonce?: string; + eventNames?: string[]; +}): string; + +function HydrationScript(props: { + nonce?: string; + eventNames?: string[]; +}): JSX.Element; +``` + +Hydration Script is a special script that should be placed once on the page to bootstrap hydration before Solid's runtime has loaded. It comes both as a function that can be called and inserted in an your HTML string, or as a Component if you are rendering JSX from the `` tag. + +The options are for the `nonce` to be put on the script tag and any event names for that Solid should capture before scripts have loaded and replay during hydration. These events are limited to those that Solid delegates which include most UI Events that are composed and bubble. By default it is only `click` and `input` events. + +# Control Flow + +For reactive control flow to be performant, we have to control how elements are created. For example, calling `array.map` is inefficient as it always maps the entire array. + +This means helper functions. Wrapping these in components is convenient way for terse templating and allows users to compose and build their own control flow components. + +These built-in control flow components will be automatically imported. All except `Portal` and `Dynamic` are exported from both `solid-js` and `solid-js/web`. `Portal` and `Dynamic`, which are DOM-specific, are exported by `solid-js/web`. + +> Note: All callback/render function children of control flow are non-tracking. This allows for nesting state creation, and better isolates reactions. + +## `` + +```ts +import { For } from "solid-js"; + +function For(props: { + each: readonly T[]; + fallback?: JSX.Element; + children: (item: T, index: () => number) => U; +}): () => U[]; +``` + +A referentially keyed loop with efficient updating of only changed items. +The callback takes the current item as the first argument: + +```jsx +Loading...}> + {(item) =>
    {item}
    } +
    +``` + +The optional second argument is an index signal: + +```jsx +Loading...}> + {(item, index) => ( +
    + #{index()} {item} +
    + )} +
    +``` + +## `` + +```ts +import { Show } from "solid-js"; + +function Show(props: { + when: T | undefined | null | false; + keyed: boolean; + fallback?: JSX.Element; + children: JSX.Element | ((item: T) => JSX.Element); +}): () => JSX.Element; +``` + +The Show control flow is used to conditional render part of the view: it renders `children` when the `when` is truthy, an `fallback` otherwise. It is similar to the ternary operator (`when ? children : fallback`) but is ideal for templating JSX. + +```jsx + 0} fallback={
    Loading...
    }> +
    My Content
    +
    +``` + +Show can also be used as a way of keying blocks to a specific data model. Ex the function is re-executed whenever the user model is replaced. + +```jsx +Loading...} keyed> + {(user) =>
    {user.firstName}
    } +
    +``` + +## ``/`` + +```ts +import { Switch, Match } from "solid-js"; +import type { MatchProps } from "solid-js"; + +function Switch(props: { + fallback?: JSX.Element; + children: JSX.Element; +}): () => JSX.Element; + +type MatchProps = { + when: T | undefined | null | false; + children: JSX.Element | ((item: T) => JSX.Element); +}; +function Match(props: MatchProps); +``` + +Useful for when there are more than 2 mutual exclusive conditions. +For example, it can be used to perform basic routing: + +```jsx +Not Found}> + + + + + + + +``` + +Match also supports function children to serve as keyed flow. + +## `` + +```ts +import { Index } from "solid-js"; + +function Index(props: { + each: readonly T[]; + fallback?: JSX.Element; + children: (item: () => T, index: number) => U; +}): () => U[]; +``` + +Non-keyed list iteration (rendered nodes are keyed to an array index). This is useful when there is no conceptual key, like if the data consists of primitives and it is the index that is fixed rather than the value. + +The item is a signal: + +```jsx +Loading...}> + {(item) =>
    {item()}
    } +
    +``` + +Optional second argument is an index number: + +```jsx +Loading...}> + {(item, index) => ( +
    + #{index} {item()} +
    + )} +
    +``` + +## `` + +```ts +import { ErrorBoundary } from "solid-js"; + +function ErrorBoundary(props: { + fallback: JSX.Element | ((err: any, reset: () => void) => JSX.Element); + children: JSX.Element; +}): () => JSX.Element; +``` + +Catches uncaught errors and renders fallback content. + +```jsx +Something went terribly wrong}> + + +``` + +Also supports callback form which passes in error and a reset function. + +```jsx +
    Error: {err.toString()}
    } +> + +
    +``` + +## `` + +```ts +import { Suspense } from "solid-js"; + +function Suspense(props: { + fallback?: JSX.Element; + children: JSX.Element; +}): JSX.Element; +``` + +A component that tracks all resources read under it and shows a fallback placeholder state until they are resolved. What makes `Suspense` different than `Show` is it is non-blocking in that both branches exist at the same time even if not currently in the DOM. + +```jsx +Loading...}> + + +``` + +## `` (Experimental) + +```ts +import { SuspenseList } from "solid-js"; + +function SuspenseList(props: { + children: JSX.Element; + revealOrder: "forwards" | "backwards" | "together"; + tail?: "collapsed" | "hidden"; +}): JSX.Element; +``` + +`SuspenseList` allows for coordinating multiple parallel `Suspense` and `SuspenseList` components. It controls the order in which content is revealed to reduce layout thrashing and has an option to collapse or hide fallback states. + +```jsx + + + Loading posts...}> + + + Loading fun facts...}> + + + +``` + +SuspenseList is still experimental and does not have full SSR support. + +## `` + +```ts +import { Dynamic } from "solid-js/web"; + +function Dynamic( + props: T & { + children?: any; + component?: Component | string | keyof JSX.IntrinsicElements; + } +): () => JSX.Element; +``` + +This component lets you insert an arbitrary Component or tag and passes the props through to it. + +```jsx + +``` + +## `` + +```ts +import { Portal } from "solid-js/web"; + +function Portal(props: { + mount?: Node; + useShadow?: boolean; + isSVG?: boolean; + children: JSX.Element; +}): Text; +``` + +This inserts the element in the mount node. Useful for inserting Modals outside of the page layout. Events still propagate through the Component Hierarchy. + +The portal is mounted in a `
    ` unless the target is the document head. `useShadow` places the element in a Shadow Root for style isolation, and `isSVG` is required if inserting into an SVG element so that the `
    ` is not inserted. + +```jsx + +
    My Content
    +
    +``` + +# Special JSX Attributes + +In general Solid attempts to stick to DOM conventions. Most props are treated as attributes on native elements and properties on Web Components, but a few of them have special behavior. + +For custom namespaced attributes with TypeScript you need to extend Solid's JSX namespace: + +```ts +declare module "solid-js" { + namespace JSX { + interface Directives { + // use:____ + } + interface ExplicitProperties { + // prop:____ + } + interface ExplicitAttributes { + // attr:____ + } + interface CustomEvents { + // on:____ + } + interface CustomCaptureEvents { + // oncapture:____ + } + } +} +``` + +## `ref` + +Refs are a way of getting access to underlying DOM elements in our JSX. While it is true one could just assign an element to a variable, it is more optimal to leave components in the flow of JSX. Refs are assigned at render time but before the elements are connected to the DOM. They come in 2 flavors. + +```js +// variable assigned directly by ref +let myDiv; + +// use onMount or createEffect to read after connected to DOM +onMount(() => console.log(myDiv)); + +
    + +// Or, callback function (called before connected to DOM) +
    console.log(el)} /> +``` + +Refs can also be used on Components. They still need to be attached on the other side. + +```jsx +function MyComp(props) { + return
    ; +} + +function App() { + let myDiv; + onMount(() => console.log(myDiv.clientWidth)); + return ; +} +``` + +## `classList` + +Solid offers two ways to set the `class` of an element: +`class` and `classList` attributes. + +First, you can set `class=...` like any other attribute. For example: + +```jsx +// Two static classes +
    + +// One dynamic class, deleting class attribute if it's not needed +
    + +// Two dynamic classes +
    +``` + +(Note that `className=...` was deprecated in Solid 1.4.) + +Alternatively, the `classList` pseudo-attribute lets you specify an object, +where each key is a class and the value is treated as a boolean +representing whether to include that class. +For example (matching the last example): + +```jsx +
    +``` + +This example compiles to a [render effect](#createrendereffect) +that dynamically calls +[`element.classList.toggle`](https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle) +to turn each class on or off, only when the corresponding boolean changes. +For example, when `state.active` becomes `true` [`false`], the element gains +[loses] the `active` class. + +The value passed into `classList` can be any expression (including a signal +getter) that evaluates to an appropriate object. Some examples: + +```jsx +// Dynamic class name and value +
    ; + +// Signal class list +const [classes, setClasses] = createSignal({}); +setClasses((c) => ({ ...c, active: true })); +
    ; +``` + +It's also possible, but dangerous, to mix `class` and `classList`. +The main safe situation is when `class` is set to a static string (or nothing), +and `classList` is reactive. +(`class` could also be set to a static computed value as in +`class={baseClass()}`, but then it should appear +before any `classList` pseudo-attributes.) +If both `class` and `classList` are reactive, +you can get unexpected behavior: +when the `class` value changes, Solid sets the entire `class` attribute, +so will overwrite any toggles made by `classList`. + +Because `classList` is a compile-time pseudo-attribute, +it does not work in a prop spread like `
    ` +or in ``. + +## `style` + +Solid's `style` attribute lets you provide either a CSS string or +an object where keys are CSS property names: + +```jsx +// string +
    + +// object +
    +``` + +Unlike [React's `style` attribute](https://reactjs.org/docs/dom-elements.html#style), +Solid uses `element.style.setProperty` under the hood. This means you need to use +the lower-case, dash-separated version of property names +instead of the JavaScript camel-cased version, +such as `"background-color"` rather than `backgroundColor`. +This actually leads to better performance and consistency with SSR output. + +```jsx +// string +
    + +// object +
    +``` + +This also means you can set CSS variables! For example: + +```jsx +// set css variable +
    +``` + +## `innerHTML`/`textContent` + +These work the same as their property equivalent. Set a string and they will be set. **Be careful!!** Setting `innerHTML` with any data that could be exposed to an end user as it could be a vector for malicious attack. `textContent` while generally not needed is actually a performance optimization when you know the children will only be text as it bypasses the generic diffing routine. + +```jsx +
    +``` + +## `on___` + +Event handlers in Solid typically take the form of `onclick` or `onClick` depending on style. + +Solid uses semi-synthetic event delegation for common UI events that are composed and bubble. This improves performance for these common events. + +```jsx +
    console.log(e.currentTarget)} /> +``` + +Solid also supports passing an array to the event handler to bind a value to the first argument of the event handler. This doesn't use `bind` or create an additional closure, so it is a highly optimized way of delegating events. + +```jsx +function handler(itemId, e) { + /*...*/ +} + +
      + {(item) =>
    • } +
    ; +``` + +Events are never rebound and the bindings are not reactive, as it is expensive to attach and detach listeners. +Since event handlers are called like any other function each time an event fires, there is no need for reactivity; shortcut your handler if desired. + +```jsx +// if defined, call it; otherwise don't. +
    props.handleClick?.()} /> +``` + +Note that `onChange` and `onInput` work according to their native behavior. `onInput` will fire immediately after the value has changed; for `` fields, `onChange` will only fire after the field loses focus. + +## `on:___`/`oncapture:___` + +For any other events, perhaps ones with unusual names, or ones you wish not to be delegated, there are the `on` namespace events. This attribute adds an event listener verbatim. + +```jsx +
    alert(e.detail)} /> +``` + +## `use:___` + +These are custom directives. In a sense this is just syntax sugar over ref but allows us to easily attach multiple directives to a single element. A directive is a function with the following signature: + +```ts +function directive(element: Element, accessor: () => any): void; +``` + +Directive functions are called at render time but before being added to the DOM. You can do whatever you'd like in them including create signals, effects, register clean-up etc. + +```js +const [name, setName] = createSignal(""); + +function model(el, value) { + const [field, setField] = value(); + createRenderEffect(() => (el.value = field())); + el.addEventListener("input", (e) => setField(e.target.value)); +} + +; +``` + +To register with TypeScript extend the JSX namespace. + +```ts +declare module "solid-js" { + namespace JSX { + interface Directives { + model: [() => any, (v: any) => any]; + } + } +} +``` + +## `prop:___` + +Forces the prop to be treated as a property instead of an attribute. + +```jsx +
    +``` + +## `attr:___` + +Forces the prop to be treated as a attribute instead of an property. Useful for Web Components where you want to set attributes. + +```jsx + +``` + +## `/* @once */` + +Solid's compiler uses a heuristic for reactive wrapping and lazy evaluation of JSX expressions. Does it contain a function call, a property access, or JSX? If yes we wrap it in a getter when passed to components or in an effect if passed to native elements. + +Knowing this heuristic and its limitations, we can reduce overhead of things we know will never change by accessing them outside of the JSX. A lone variable will never be wrapped. We can also tell the compiler not to wrap them by starting the expression with a comment decorator `/* @once */`. + +```jsx + +``` + +This also works on children. + +```jsx +{/*@once*/ state.wontUpdate} +``` diff --git a/langs/tr/guides/comparison.md b/langs/tr/guides/comparison.md new file mode 100644 index 00000000..ca05c953 --- /dev/null +++ b/langs/tr/guides/comparison.md @@ -0,0 +1,77 @@ +# Comparison with other Libraries + +This section cannot escape some bias but I think it is important to understand where Solid's solution sits compared to other libraries. This is not about performance. For a definitive look at performance feel free to look at the [JS Framework Benchmark](https://github.com/krausest/js-framework-benchmark). + +## React + +React has had a big influence on Solid. Its unidirectional flow and explicit segregation of read and write in its Hooks API informed Solid's API. More so than the objective of being just a "Render Library" rather than a framework. Solid has strong opinions on how to approach managing data in application development but doesn't seek to constrain its execution. + +However, as much as Solid aligns with React's design philosophy, it works fundamentally differently. React uses a Virtual DOM and Solid does not. React's abstraction is top down component partition where render methods are called repeatedly and diffed. Solid, instead, renders each Template once in its entirety, constructing its reactive graph and only then executes instructions related to fine-grained changes. + +#### Advice for migrating: + +Solid's update model is nothing like React, or even React + MobX. Instead of thinking of function components as the `render` function, think of them as a `constructor`. + +In Solid, props and stores are [proxy objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) that rely on property access for tracking and reactive updates. Watch out for destructuring or early property access, which can cause these properties to lose reactivity or trigger at the wrong time. + +Solid's primitives have no restrictions like the Hook Rules so you are free to nest them as you see fit. + +You don't need explicit keys on list rows to have "keyed" behavior. + +In React, `onChange` fires whenever an input field is modified, but this isn't how `onChange` [works natively](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onchange). In Solid, use `onInput` to subscribe to each value change. + +Finally, there is no VDOM so imperative VDOM APIs like `React.Children` and `React.cloneElement` have no equivalent in Solid. Instead of creating or modifying DOM elements directly, express your intentions declaratively. + +## Vue + +Solid is not particularly influenced by Vue design-wise, but they are comparable in approach. They both use Proxies in their Reactive system with read based auto-tracking. But that is where the similarities end. Vue's fine-grained dependency detection just feeds into a less fine-grained Virtual DOM and Component system whereas Solid keeps its granularity right down to its direct DOM updates. + +Vue values easiness where Solid values transparency. Although Vue's new direction with Vue 3 aligns more with the approach Solid takes. These libraries might align more over time depending on how they continue to evolve. + +#### Advice for migrating: + +As another modern reactive library migration from Vue 3 should feel familiar. Solid's components are very much like tagging the template on the end of Vue's `setup` function. Be wary of overwrapping state derivations with computations, try a function. Reactivity is pervasive. Solid's proxies are intentionally read-only. Don't knock it before you try it. + +## Svelte + +Svelte pioneered the precompiled disappearing framework that Solid also employs to a certain degree. Both libraries are truly reactive and can produce really small execution code bundles although Svelte is the winner here for small demos. Solid requires a bit more explicitness in its declarations, relying less on implicit analysis from the compiler, but that is part of what gives Solid superior performance. Solid also keeps more in the runtime which scales better in larger apps. Solid's RealWorld demo implementation is 25% smaller than Svelte's. + +Both libraries aim to help their developers write less code but approach it completely differently. Svelte 3 focuses on the optimization of the ease of dealing with localized change focusing on plain object interaction and two-way binding. In contrast Solid focuses on the data flow by deliberately embracing CQRS and immutable interface. With functional template composition, in many cases, Solid allows developers to write even less code than Svelte although Svelte's template syntax is definitely terser. + +#### Advice for migrating: + +Developer experience is different enough that while some things are analogous it is a very different experience. Components in Solid are cheap, so don't shy away from having more of them. + +## Knockout.js + +This library owes its existence to Knockout. Modernizing its model for fine-grained dependency detection was the motivation for this project. Knockout was released in 2010 and supports Microsoft Explorer back to IE6 while much of Solid doesn't support IE at all. + +Knockout's bindings are just strings in HTML which are walked over at runtime. They depend on cloning context ($parent etc...). Whereas Solid uses JSX or Tagged Template Literals for templating opting for an in JavaScript API. + +The biggest difference might be that Solid's approach to batching changes which ensures synchronicity whereas Knockout has deferUpdates which uses a deferred microtask queue. + +#### Advice for migrating: + +If you are used to Knockout, Solid's primitives might look strange to you. The read/write separation is intentional and not just to make life harder. Look to adopting a state/action (Flux) mental model. While the libraries look similar they promote different best practices. + +## Lit & LighterHTML + +These libraries are incredibly similar and have had some influence on Solid. Mostly that Solid's compiled code uses a very similar method to performantly initially render the DOM. Cloning Template elements and using comment placeholders are something that Solid and these libraries share in common. + +The biggest difference is that while these libraries do not use the Virtual DOM they treat rendering the same way, top down, requiring component partitioning to keep things sane. By contrast, Solid uses its fine-grained Reactive Graph to only update what has changed and in doing so only shares this technique for its initial render. This approach takes advantage from the initial speed only available to native DOM and also have the most performant approach to updates. + +#### Advice for migrating: + +These libraries are pretty minimal and easy to build on top. However, keep in mind that `` isn't just HTMLElement (array or function). Try to keep your things in the JSX template. Hoisting works for the most part but it is best to mentally think of this still as a render library and not a HTMLElement factory. + +## S.js + +This library had the greatest influence on Solid's reactive design. Solid used S.js internally for a couple of years until the feature set placed them on different paths. S.js is one of the most efficient reactive libraries to date. It models everything off synchronous time steps like a digital circuit and ensures consistency without having to do many of the more complicated mechanisms found in libraries like MobX. Solid's reactivity in the end is a sort of hybrid between S and MobX. This gives it greater performance than most reactive libraries (Knockout, MobX, Vue) while retaining the ease of mental model for the developer. S.js ultimately is still the more performant reactive library although the difference is hardly noticeable in all but the most grueling synthetic benchmarks. + +## RxJS + +RxJS is a Reactive library. While Solid has a similar idea of Observable data it uses a much different application of the observer pattern. While Signals are like a restricted form of an Observable (only the next), the pattern of auto dependency detection supplants RxJS' hundred or so operators. Solid could have taken this approach, and indeed earlier, versions of the library included similar operators, but in most cases it is more straightforward to write your own transformation logic in a computation. Where Observables are cold starting, unicast and push-based, many problems on the client lend themselves to hot startup and being multicast which is Solid's default behavior. + +## Others + +Angular and a few other popular libraries are notably missing from this comparison. Lack of experience with them prevents making any adequate comparisons. Generally, Solid has little in common with larger Frameworks and it is much harder to compare them head on. diff --git a/langs/tr/guides/directory.json b/langs/tr/guides/directory.json new file mode 100644 index 00000000..9e07b0d4 --- /dev/null +++ b/langs/tr/guides/directory.json @@ -0,0 +1,42 @@ +[ + { + "resource": "getting-started", + "title": "Getting Started", + "description": "A guide for how to get started with Solid." + }, + { + "resource": "reactivity", + "title": "Reactivity", + "description": "Full rundown of Solid's reactivity." + }, + { + "resource": "rendering", + "title": "Rendering", + "description": "Discusses the different templating and rendering options in Solid." + }, + { + "resource": "server", + "title": "Server", + "description": "An explanation of Solid's server-side capabilities." + }, + { + "resource": "typescript", + "title": "TypeScript", + "description": "Tips for using Solid with TypeScript" + }, + { + "resource": "testing", + "title": "Testing Solid", + "description": "How to test your Solid app" + }, + { + "resource": "comparison", + "title": "Comparison", + "description": "Comparisons of Solid against other frameworks." + }, + { + "resource": "faq", + "title": "FAQ", + "description": "Frequently asked questions from the community." + } +] diff --git a/langs/tr/guides/faq.md b/langs/tr/guides/faq.md new file mode 100644 index 00000000..d67383b9 --- /dev/null +++ b/langs/tr/guides/faq.md @@ -0,0 +1,132 @@ +# FAQ + +### JSX without a virtual DOM? Is this vaporware? I've heard prominent voices say that this isn't possible. + +It is possible when you don't have React's update model. JSX is a template language like those in Svelte or Vue—just one that is more flexible in certain ways. Inserting arbitrary JavaScript can be challenging at times, but no different than supporting spread operators. So, no: this isn't vaporware, but an approach proven to be one of the most performant. + +The real benefit comes in how extensible it is. We have a compiler working for you to give you optimal native DOM updates, but you have all the freedom of a library like React. You can write components using standard techniques like [render props](https://reactjs.org/docs/render-props.html) and higher order components along side your reactive "hooks". Don't like how Solid's control flow works? Write your own. + +### How is Solid so performant? + +We wish we could point to a single thing, but it really is the combination of several important design decisions: + +1. Explicit reactivity, so only the things that should be reactive are tracked. +2. Compilation with initial creation in mind. Solid uses heuristics and combines the right expressions to reduce the number of computations, but keep key updates granular and performant. +3. Reactive expressions are just functions. This enables "vanishing components" with lazy prop evaluation removing unnecessary wrappers and synchronization overhead. + +These are currently unique techniques in a combination that gives Solid an edge over the competition. + +### Is there React-Compat, or some way to use my React libraries in Solid? + +No. And there likely never will be. While the APIs are similar and components often can be moved across with minor edits, the update model is fundamentally different. React Components render over and over so code outside of Hooks works very differently. The closures and hook rules are not only unnecessary in Solid: they can prescribe code that does not work here. + +Vue-Compat, on the other hand, would be doable, although there are no plans to implement it currently. + +On the other hand, it is possible to run Solid _within_ React. [React Solid State](https://github.com/solidjs/react-solid-state) makes the Solid API accessible in React function components. [reactjs-solidjs-bridge](https://github.com/Sawtaytoes/reactjs-solidjs-bridge) lets you render React components within Solid components and vice versa, which is useful when gradually porting an app. + +### Why shouldn't I use `map` in my template, and what's the difference between `` and ``? + +If your array is static, there's nothing wrong with using map. But if you're looping over a signal or reactive property, `map` is inefficient: if the array changes for any reason, _the entire map_ will rerun and all of the nodes will be recreated. + +`` and `` both provide a loop solution that is smarter than this. They couple each rendered node with an element in the array, so when an array element changes, only the corresponding node will rerender. + +`` will do this _by index_: each node corresponds to an index in the array; `` will do this _by value_: each node corresponds to a piece of data in the array. This is why, in the callback, `` gives you a signal for the item: the index for each item is considered fixed, but the data at that index can change. On the other hand, `` gives you a signal for the index: the content of the item is considered fixed, but it can move around if elements get moved in the array. + +For example, if two elements in the array are swapped, `` will reposition the two corresponding DOM nodes and update their `index()` signals along the way. `` won't reposition any DOM nodes, but will update the `item()` signals for the two DOM nodes and cause them to rerender. + +For an in-depth demonstration of the difference, see [this segment](https://www.youtube.com/watch?v=YxroH_MXuhw&t=2164s) of Ryan's stream. + +### Why do I lose reactivity when I destructure props? + +With a props object, reactivity is enabled by tracking on property access. +If you access the property within a _tracking scope_ +like a JSX expression or an effect, then the JSX expression will rerender or the effect will rerun when that property changes. + +When you destructure, you access the properties of the object. If this takes place outside of a tracking scope, Solid won't track and rerun +your code. + +In this example, the property access happens within the JSX template, so it's +tracked and the span contents update when the signal changes: + +```jsx +function BlueText(props) { + return ( + {props.text} + ); +} +... + +``` + +But neither of these examples will update the span text because the property access happens +outside of the template: + +```jsx +function BlueText(props) { + const text = props.text; + return ( + {text} + ); +} +... + +``` + +```jsx +function BlueText({text}) { + return ( + {text} + ); +} +... + +``` + +If you prefer the style of early destructuring, though, there are two different Babel +transforms you can use to make (certain styles of) destructuring reactive +again: [babel-plugin-solid-undestructure](https://github.com/orenelbaum/babel-plugin-solid-undestructure) +and [Solid Labels'](https://github.com/LXSMNSYC/solid-labels) [object features](https://github.com/LXSMNSYC/solid-labels/blob/main/docs/ctf.md#objects). + +### Why isn't my `onChange` event handler firing on time? + +In some frameworks, the `onChange` event for inputs is modified so that it fires on every key press. But this isn't how the `onChange` event [works natively](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onchange): it is meant to reflect a _committed_ change to the input and will usually fire when the input loses focus. To handle all changes to the value of an input, use `onInput`. + +### Can you add support for class components? I find the lifecycles are easier to reason about. + +We don't intend to support class components. The lifecycles of components in Solid are tied to the scheduling of the reactive system and are artificial. You could make a class out of it, but effectively all of the non-event handler code would be run in the constructor, including the render function. It's just more syntax for an excuse to make your data less granular. + +Group data and its behaviors together, rather than lifecycles. This is a reactive best practice that has worked for decades. + +### I really dislike JSX, any chance of a different template language? Oh, I see you have Tagged Template Literals/HyperScript. Maybe I will use those... + +We use JSX the way Svelte uses their templates, to create optimized DOM instructions. The Tagged Template Literal and HyperScript solutions may be really impressive in their own right, but unless you have a real reason like a no-build requirement they are inferior in every way. Larger bundles, slower performance, and the need for manual workaround wrapping values. + +It's good to have options, but Solid's JSX is really the best solution here. A Template DSL would be great as well, albeit more restrictive, but JSX gives us so much for free. Existing Parsers, Syntax Highlighting, Prettier, Code Completion, and last but not least TypeScript. + +Other libraries have been adding support for these features but that has been an enormous effort and is still imperfect and a constant maintenance headache. This is really taking a pragmatic stance. + +### When do I use a Signal vs Store? Why are these different? + +Stores automatically wrap nested values making it ideal for deep data structures, and for things like models. For most other things Signals are lightweight and do the job wonderfully. + +As much we would love to wrap these together as a single thing, you can't proxy primitive values, so in this case we use functions. Any reactive expression (including state access) can be wrapped in a function on transport, so this provides a universal API. You can name your signals and state as you choose and it stays minimal. Last thing we'd want to do is force typing `.get()` `.set()` on the end-user or even worse `.value`. At least the former can be aliased for brevity, whereas the latter is just the least terse way to call a function. + +### Why can I not just assign a value to Solid's Store as I can in Vue, Svelte, or MobX? Where is the 2-way binding? + +Reactivity is a powerful tool but also a dangerous one. MobX knows this and introduced Strict mode and Actions to limit where/when updates occur. In Solid, which deals with whole Component trees of data, it became apparent that we can learn something from React here. You don't need to be actually immutable as long as you provide the means to have the same contract. + +Being able to pass the ability to update state is arguably even more important than deciding to pass the state. So being able to separate it is important, and only possible if reading is immutable. We also don't need to pay the cost of immutability if we can still granularly update. Luckily there are tons of prior art here between ImmutableJS and Immer. Ironically Solid acts mostly as a reverse Immer with its mutable internals and immutable interface. + +### Can I use Solid's reactivity on its own? + +Of course. While we haven't exported a standalone package it is easy to install Solid without the compiler and just use the reactive primitives. One of the benefits of granular reactivity is it is library agnostic. For that matter, almost every reactive library works this way. That is what inspired [Solid](https://github.com/solidjs/solid) and its underlying [DOM Expressions library](https://github.com/ryansolid/dom-expressions) in the first place to make a renderer purely from the reactive system. + +To list a few to try: [Solid](https://github.com/solidjs/solid), [MobX](https://github.com/mobxjs/mobx), [Knockout](https://github.com/knockout/knockout), [Svelte](https://github.com/sveltejs/svelte), [S.js](https://github.com/adamhaile/S), [CellX](https://github.com/Riim/cellx), [Derivable](https://github.com/ds300/derivablejs), [Sinuous](https://github.com/luwes/sinuous), and even recently [Vue](https://github.com/vuejs/vue). Much more goes into making a reactive library than tagging it onto a renderer like, [lit-html](https://github.com/Polymer/lit-html) for example, but it's a good way to get a feel. + +### Does Solid have a Next.js or Material Components like library I can use? + +We're working on [SolidStart](https://github.com/solidjs/solid-start), which is our SSR starter solution similar to Next.js or SvelteKit. + +For component libraries, we've got [SUID](https://suid.io/) for Material, [Hope UI](https://hope-ui.com/) for a Chakra-like solution, [Solid Bootstrap](https://solid-libs.github.io/solid-bootstrap/) and plenty more! Check out our [rapidly growing ecosystem of libraries and tools](https://www.solidjs.com/ecosystem). + +If you are interested in building your own ecosystem tool, we are readily available on our [Discord](https://discord.com/invite/solidjs), where you can join existing ecosystem efforts or start your own. diff --git a/langs/tr/guides/getting-started.md b/langs/tr/guides/getting-started.md new file mode 100644 index 00000000..6f8e39b9 --- /dev/null +++ b/langs/tr/guides/getting-started.md @@ -0,0 +1,170 @@ +# Getting Started + +**We're working on new docs.** You can check out our new beginner tutorial [here](https://docs.solidjs.com/tutorials/getting-started-with-solid/), and join our efforts on [Discord!](http://discord.com/invite/solidjs) + +## See Solid + +For quick video overviews of Solid's core concepts, check out: + +- [Solid in 100 seconds](https://youtu.be/hw3Bx5vxKl0) +- [Solid reactivity in 10 minutes](https://youtu.be/J70HXl1KhWE) + +## Try Solid + +By far the easiest way to get started with Solid is to try it online. Our REPL at https://playground.solidjs.com is the perfect way to try out ideas. As is https://codesandbox.io/ where you can modify any of [our Examples](https://github.com/solidjs/solid/blob/main/documentation/resources/examples.md). + +Alternatively, you can use our [Vite templates](https://github.com/solidjs/templates) by running these commands in your terminal: + +```sh +> npx degit solidjs/templates/js my-app +> cd my-app +> npm i # or yarn or pnpm +> npm run dev # or yarn or pnpm +``` + +Or for TypeScript: + +```sh +> npx degit solidjs/templates/ts my-app +> cd my-app +> npm i # or yarn or pnpm +> npm run dev # or yarn or pnpm +``` + +Or you can install the dependencies in your own project. To use Solid with JSX +(recommended), you need to install the `solid-js` NPM library and the +[Solid JSX compiler](https://github.com/ryansolid/dom-expressions/tree/main/packages/babel-plugin-jsx-dom-expressions) +Babel plugin: + +```sh +> npm install solid-js babel-preset-solid +``` + +Then add `babel-preset-solid` to your `.babelrc`, or to your Babel config in webpack or rollup: + +```json +"presets": ["solid"] +``` + +For TypeScript, set your `tsconfig.json` to handle Solid's JSX as follows +(see the [TypeScript guide](https://www.solidjs.com/guides/typescript) +for more details): + +```json +"compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js", +} +``` + +## Learn Solid + +Solid is all about small composable pieces that serve as building blocks for applications. These pieces are mostly functions which make up many shallow top-level APIs. Fortunately, you won't need to know about most of them to get started. + +The two main types of building blocks you have at your disposal are Components and Reactive Primitives. + +Components are functions that accept a props object and return JSX elements including native DOM elements and other components. They can be expressed as JSX Elements in PascalCase: + +```jsx +function MyComponent(props) { + return
    Hello {props.name}
    ; +} + +; +``` + +Components are lightweight in that they are not stateful themselves and have no instances. Instead, they serve as factory functions for DOM elements and reactive primitives. + +Solid's fine-grained reactivity is built on three core primitives: Signals, Memos, and Effects. Together, they form an auto-tracking synchronization engine that ensures your view stays up to date. Reactive computations take the form of function-wrapped expressions that execute synchronously. + +```js +const [first, setFirst] = createSignal("JSON"); +const [last, setLast] = createSignal("Bourne"); + +createEffect(() => console.log(`${first()} ${last()}`)); +``` + +You can learn more about [Solid's Reactivity](/guides/reactivity) and [Solid's Rendering](/guides/rendering). + +## Think Solid + +Solid's design carries several opinions on what principles and values help us best build websites and applications. It is easier to learn and use Solid when you are aware of the philosophy behind it. + +### 1. Declarative Data + +Declarative data is the practice of tying the description of data’s behavior to its declaration. This allows for easy composition by packaging all aspects of data’s behavior in a single place. + +### 2. Vanishing Components + +It's hard enough to structure your components without taking updates into consideration. Solid updates are completely independent of the components. Component functions are called once and then cease to exist. Components exist to organize your code and not much else. + +### 3. Read/Write segregation + +Precise control and predictability make for better systems. We don't need true immutability to enforce unidirectional flow, just the ability to make the conscious decision which consumers may write and which may not. + +### 4. Simple is better than easy + +A lesson that comes hard for fine-grained reactivity. Explicit and consistent conventions even if they require more effort are worth it. The aim is to provide minimal tools to serve as the basis to build upon. + +## Web Components + +Solid was born with the desire to have Web Components as first class citizens. Over time its design has evolved and goals have changed. However, Solid is still a great way to author Web Components. [Solid Element](https://github.com/solidjs/solid/tree/main/packages/solid-element) allows you to write and wrap Solid's function components to produce small and performant Web Components. Inside Solid apps Solid Element is able to still leverage Solid's Context API, and Solid's Portals support Shadow DOM isolated styling. + +## Server Rendering + +Solid has a dynamic server side rendering solution that enables a truly isomorphic development experience. Through the use of our Resource primitive, async data requests are easily made and, more importantly, automatically serialized and synchronized between client and browser. + +Since Solid supports asynchronous and stream rendering on the server, you get to write your code one way and have it execute on the server. This means that features like [render-as-you-fetch](https://reactjs.org/docs/concurrent-mode-suspense.html#approach-3-render-as-you-fetch-using-suspense) and code splitting just work in Solid. + +For more information, read the [Server guide](/guides/server#server-side-rendering). + +## Buildless options + +If you need or prefer to use Solid in non-compiled environments such as plain HTML files, https://codepen.io, etc, you can use [` html`` ` Tagged Template Literals](https://github.com/solidjs/solid/tree/main/packages/solid/html) or [HyperScript `h()` functions](https://github.com/solidjs/solid/tree/main/packages/solid/h) in plain JavaScript instead of Solid's compile-time-optimized JSX syntax. + +You can run them straight from the browser using [Skypack](https://www.skypack.dev/), for example: + +```html + + + + + +``` + +The advantages of going buildless come with tradeoffs: + +- Expressions need to always be a wrapped in a getter function or they won't be reactive. + The following will not update when the `first` or `last` values change because the values are not being accessed inside an effect that the template creates internally, therefore dependencies will not be tracked: + ```js + html`

    Hello ${first() + " " + last()}

    `; + // or + h("h1", {}, "Hello ", first() + " " + last()); + ``` + The following will update as expected when `first` or `last` change because the template will read from the getter within an effect and dependencies will be tracked: + ```js + html`

    Hello ${() => first() + " " + last()}

    `; + // or + h("h1", {}, "Hello ", () => first() + " " + last()); + ``` + Solid's JSX doesn't have this issue because of its compile-time abilities, and an expression like `

    Hello {first() + ' ' + last()}

    ` will be reactive. +- Build-time optimizations won't be in place like they are with Solid JSX, meaning app startup speed will be slightly slower because each template gets compiled at runtime the first time it is executed, but for many use cases this perf hit is imperceivable. Ongoing speed after startup will remain the same with the ` html`` ` template tag as with JSX. `h()` calls will always have slower ongoing speed due to their inability to statically analyze whole templates before being executed. + +You need the corresponding DOM Expressions library for these to work with TypeScript. You can use Tagged Template Literals with [Lit DOM Expressions](https://github.com/ryansolid/dom-expressions/tree/main/packages/lit-dom-expressions) or HyperScript with [Hyper DOM Expressions](https://github.com/ryansolid/dom-expressions/tree/main/packages/hyper-dom-expressions). diff --git a/langs/tr/guides/reactivity.md b/langs/tr/guides/reactivity.md new file mode 100644 index 00000000..bb3da055 --- /dev/null +++ b/langs/tr/guides/reactivity.md @@ -0,0 +1,95 @@ +# Reactivity + +Solid's data management is built off a set of flexible reactive primitives which are responsible for all the updates. It takes a very similar approach to MobX or Vue except it never trades its granularity for a VDOM. Dependencies are automatically tracked when you access your reactive values in your Effects and JSX View code. + +Solid's primitives come in the form of `create` calls that often return tuples, where generally the first element is a readable primitive and the second is a setter. It is common to refer to only the readable part by the primitive name. + +Here is a basic auto incrementing counter that is updating based on setting the `count` signal. + +```jsx +import { createSignal, onCleanup } from "solid-js"; +import { render } from "solid-js/web"; + +const App = () => { + const [count, setCount] = createSignal(0), + timer = setInterval(() => setCount(count() + 1), 1000); + onCleanup(() => clearInterval(timer)); + + return
    {count()}
    ; +}; + +render(() => , document.getElementById("app")); +``` + +## Introducing Primitives + +Solid is made up of 3 primary primitives: Signal, Memo, and Effect. At their core is the Observer pattern where Signals (and Memos) are tracked by wrapping Memos and Effects. + +Signals are the most core primitive. They contain value, and get and set functions so we can intercept when they are read and written to. + +```js +const [count, setCount] = createSignal(0); +``` + +Effects are functions that wrap reads of our signal and re-execute whenever a dependent Signal's value changes. This is useful for creating side effects, like rendering. + +```js +createEffect(() => console.log("The latest count is", count())); +``` + +Finally, Memos are cached derived values. They share the properties of both Signals and Effects. They track their own dependent Signals, re-executing only when those change, and are trackable Signals themselves. + +```js +const fullName = createMemo(() => `${firstName()} ${lastName()}`); +``` + +## How it Works + +Signals are event emitters that hold a list of subscriptions. They notify their subscribers whenever their value changes. + +Where things get more interesting is how these subscriptions happen. Solid uses automatic dependency tracking. Updates happen automatically as the data changes. + +The trick is a global stack at runtime. Before an Effect or Memo executes (or re-executes) its developer-provided function, it pushes itself on to that stack. Then any Signal that is read checks if there is a current listener on the stack and if so adds the listener to its subscriptions. + +You can think of it like this: + +```js +function createSignal(value) { + const subscribers = new Set(); + + const read = () => { + const listener = getCurrentListener(); + if (listener) subscribers.add(listener); + return value; + }; + + const write = (nextValue) => { + value = nextValue; + for (const sub of subscribers) sub.run(); + }; + + return [read, write]; +} +``` + +Now whenever we update the Signal we know which Effects to re-run. Simple yet effective. The actual implementation is much more complicated but that is the guts of what is going on. + +For more detailed understanding of how Reactivity works these are useful articles: + +[A Hands-on Introduction to Fine-Grained Reactivity](https://dev.to/ryansolid/a-hands-on-introduction-to-fine-grained-reactivity-3ndf) + +[Building a Reactive Library from Scratch](https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p) + +[SolidJS: Reactivity to Rendering](https://indepth.dev/posts/1289/solidjs-reactivity-to-rendering) + +## Considerations + +This approach to reactivity is very powerful and dynamic. It can handle dependencies changing on the fly through executing different branches of conditional code. It also works through many levels of indirection. Any function executed inside a tracking scope is also being tracked. + +However, there are some key behaviors and tradeoffs we must be aware of. + +1. All reactivity is tracked from function calls whether directly or hidden beneath getter/proxy and triggered by property access. This means where you access properties on reactive objects is important. + +2. Components and callbacks from control flows are not tracking scopes and only execute once. This means destructuring or doing logic top-level in your components will not re-execute. You must access these Signals, Stores, and props from within other reactive primitives or the JSX for that part of the code to re-evaluate. + +3. This approach only tracks synchronously. If you have a setTimeout or use an async function in your Effect the code that executes async after the fact won't be tracked. diff --git a/langs/tr/guides/rendering.md b/langs/tr/guides/rendering.md new file mode 100644 index 00000000..a330dee1 --- /dev/null +++ b/langs/tr/guides/rendering.md @@ -0,0 +1,282 @@ +# Rendering + +Solid supports templating in 3 forms JSX, Tagged Template Literals and Solid's HyperScript variant, although JSX is the predominate form. Why? JSX is a great DSL made for compilation. It has clear syntax, supports TypeScript, works with Babel and supports other tooling like Code Syntax Highlighting and Prettier. It was only pragmatic to use a tool that basically gives you that all for free. As a compiled solution it provides great DX. Why struggle with custom Syntax DSLs when you can use one so widely supported? + +## JSX Compilation + +Rendering involves precompilation of JSX templates into optimized native js code. The JSX code constructs: + +- Template DOM elements which are cloned on each instantiation +- A series of reference declarations using only firstChild and nextSibling +- Fine grained computations to update the created elements. + +This approach is both more performant and produces less code than creating each element, one by one, with document.createElement. + +## Attributes and Props + +Solid attempts to reflect HTML conventions as much as possible including case insensitivity of attributes. + +The majority of all attributes on native element JSX are set as DOM attributes. Static values are built right into the template that is cloned. There are a number of exceptions like `class`, `style`, `value`, `innerHTML` which provide extra functionality. + +However, custom elements (with exception of native built-ins) default to properties when dynamic. This is to handle more complex data types. It does this conversion by camel casing standard snake case attribute names `some-attr` to `someAttr`. + +However, it is possible to control this behavior directly with namespace directives. You can force an attribute with `attr:` or force prop `prop:` + +```jsx + +``` + +> **Note:** Static attributes are created as part of the html template that is cloned. Expressions fixed and dynamic are applied afterwards in JSX binding order. While this is fine for most DOM elements there are some, like input elements with `type='range'`, where order matters. Keep this in mind when binding elements. + +## Entry + +The easiest way to mount Solid is to import render from 'solid-js/web'. `render` takes a function as the first argument and the mounting container for the second and returns a disposal method. This `render` automatically creates the reactive root and handles rendering into the mount container. For best performance use an element with no children. + +```jsx +import { render } from "solid-js/web"; + +render(() => , document.getElementById("main")); +``` + +> **Important** The first argument needs to be a function. Otherwise we can't properly track and schedule the reactive system. Omitting the function wrapper will cause your Effects not to run. + +## Components + +Components in Solid are just Pascal (Capital) cased functions. Their first argument is a props object and they return real DOM nodes. + +```jsx +const Parent = () => ( +
    + +
    +); + +const Label = (props) => ( + <> +
    {props.greeting}
    + {props.children} + +); +``` + +Since all JSX nodes are actual DOM nodes, the only responsibility of top level Components is to append them to the DOM. + +## Props + +Much like React, Vue, Angular and other frameworks, Solid allows you to define properties on your components to pass data to child components. Here a parent is passing the string "Hello" to the `Label` component via a `greeting` property. + +```jsx +const Parent = () => ( +
    + +
    +); +``` + +In the above example, the value set on `greeting` is static, but we can also set dynamic values. For example: + +```jsx +const Parent = () => { + const [greeting, setGreeting] = createSignal("Hello"); + + return ( +
    + +
    + ); +}; +``` + +Components can access properties passed to them via a `props` argument. + +```jsx +const Label = (props) => ( + <> +
    {props.greeting}
    + {props.children} + +); +``` + +Unlike in some other frameworks, you cannot use object destructuring on the `props` of a component. This is because the `props` object, behind the scenes, relies on Object getters to lazily retrieve values. Using object destructuring breaks the reactivity of `props`. + +This example shows the "correct" way of accessing props in Solid: + +```jsx +// Here, `props.name` will update like you'd expect +const MyComponent = (props) =>
    {props.name}
    ; +``` + +This example shows the wrong way of accessing props in Solid: + +```jsx +// This is bad +// Here, `props.name` will not update (i.e. is not reactive) as it is destructured into `name` +const MyComponent = ({ name }) =>
    {name}
    ; +``` + +While the props object looks like a normal object when you use it (and TypeScript users will note that it is typed like a normal object), in reality it is reactive – somewhat similar to a Signal. This has a few implications. + +Because unlike most JSX frameworks, Solid's function components are only executed once (rather than every render cycle), the following example will not work as expected. + +```jsx +import { createSignal } from "solid-js"; + +const BasicComponent = (props) => { + const value = props.value || "default"; + + return
    {value}
    ; +}; + +export default function Form() { + const [value, setValue] = createSignal(""); + + return ( +
    + + setValue(e.currentTarget.value)} /> +
    + ); +} +``` + +In this example, what we probably want to happen is for the `BasicComponent` to display the current value typed into the `input`. But, as a reminder, the `BasicComponent` function will only be executed once when the component is initially created. At this time (at creation), `props.value` will equal `''`. This means that `const value` in `BasicComponent` will resolve to `'default'` and never update. While the `props` object is reactive, accessing the props in `const value = props.value || 'default';` is outside the observable scope of Solid, so it isn't automatically re-evaluated when props change. + +So how can we fix our problem? + +Well, in general, we need to access `props` somewhere that Solid can observe it. Generally this means inside JSX or inside a `createMemo`, `createEffect`, or thunk(`() => ...`). Here is one solution that works as expected: + +```jsx +const BasicComponent = (props) => { + return
    {props.value || "default"}
    ; +}; +``` + +This, equivalently, can be hoisted into a function: + +```jsx +const BasicComponent = (props) => { + const value = () => props.value || "default"; + + return
    {value()}
    ; +}; +``` + +Another option, if it is an expensive computation, is to use `createMemo`. For example: + +```jsx +const BasicComponent = (props) => { + const value = createMemo(() => props.value || "default"); + + return
    {value()}
    ; +}; +``` + +Or using a helper + +```jsx +const BasicComponent = (props) => { + props = mergeProps({ value: "default" }, props); + + return
    {props.value}
    ; +}; +``` + +As a reminder, the following examples will _not_ work: + +```jsx +// bad +const BasicComponent = (props) => { + const { value: valueProp } = props; + const value = createMemo(() => valueProp || "default"); + return
    {value()}
    ; +}; + +// bad +const BasicComponent = (props) => { + const valueProp = props.value; + const value = createMemo(() => valueProp || "default"); + return
    {value()}
    ; +}; +``` + +Solid's Components are the key part of its performance. Solid's approach of "Vanishing" Components is made possible by lazy prop evaluation. Instead of evaluating prop expressions immediately and passing in values, execution is deferred until the prop is accessed in the child. Doing so we postpone execution until the last moment, typically right in the DOM bindings, maximizing performance. This flattens the hierarchy and removes the need to maintain a tree of Components. + +```jsx +; + +// compiles roughly to: + +// we untrack the component body to isolate it and prevent costly updates +untrack(() => + Component({ + prop1: "static", + // dynamic expression so we wrap in a getter + get prop2() { + return state.dynamic; + }, + }) +); +``` + +To help maintain reactivity Solid has a couple of prop helpers: + +```jsx +// default props +props = mergeProps({ name: "Smith" }, props); + +// clone props +const newProps = mergeProps(props); + +// merge props +props = mergeProps(props, otherProps); + +// split props into multiple props objects +const [local, others] = splitProps(props, ["class"]) +
    +``` + +## Children + +Solid handles JSX Children similar to React. A single child is a single value on `props.children` and multiple children is handled via an array of values. Normally, you pass them through to the JSX view. However, if you want to interact with them the suggested method is the `children` helper which resolves any downstream control flows and returns a memo. + +```jsx +// single child +const Label = (props) =>
    Hi, { props.children }
    + + + +// multi child +const List = (props) =>
    {props.children}
    ; + + +
    First
    + {state.expression} + +
    + +// map children +const List = (props) =>
      + {item =>
    • {item}
    • }
      +
    ; + +// modify and map children using helper +const List = (props) => { + // children helper memoizes value and resolves all intermediate reactivity + const memo = children(() => props.children); + createEffect(() => { + const children = memo(); + children.forEach((c) => c.classList.add("list-child")) + }) + return
      + {item =>
    • {item}
    • }
      +
    ; +``` + +**Important:** Solid treats child tags as expensive expressions and wraps them the same way as dynamic reactive expressions. This means they evaluate lazily on `prop` access. Be careful accessing them multiple times or destructuring before the place you would use them in the view. This is because Solid doesn't have the luxury of creating Virtual DOM nodes ahead of time and then diffing them, so resolution of these `props` must be lazy and deliberate. Use `children` helper if you wish to do this as it memoizes them. diff --git a/langs/tr/guides/server.md b/langs/tr/guides/server.md new file mode 100644 index 00000000..4d3d64b6 --- /dev/null +++ b/langs/tr/guides/server.md @@ -0,0 +1,140 @@ +# Server Side Rendering + +Solid handles Server rendering by compiling JSX templates to ultra efficient string appending code. This can be achieved through the babel plugin or preset by passing in `generate: "ssr"`. For both client and server you need to pass in `hydratable: true` to generate the hydration compatible code. + +The `solid-js` and `solid-js/web` runtimes are swapped for non-reactive counterparts when running in a node environment. For other environments you will need to bundle the server code with conditional exports set to `node`. Most bundlers have a way of doing this. In general we also recommend using the `solid` export conditions as well as it is recommend that libraries ship their source under the `solid` export. + +Building for SSR definitely takes a bit more configuration because we will be generating 2 separate bundles. The client entry should use `hydrate`: + +```jsx +import { hydrate } from "solid-js/web"; + +hydrate(() => , document); +``` + +_Note: It is possible to render and hydrate from the Document root. This allows us to describe our full view in JSX._ + +The server entry can use one of the four rendering options offered by Solid. Each produces the output and a script tag to be inserted in the head of the document. + +```jsx +import { + renderToString, + renderToStringAsync, + renderToStream +} from "solid-js/web"; + +// Synchronous string rendering +const html = renderToString(() => ); + +// Asynchronous string rendering +const html = await renderToStringAsync(() => ); + +// Stream rendering +const stream = renderToStream(() => ); + +// Node +stream.pipe(res); + +// Web streams (for like Cloudflare Workers) +const { readable, writable } = new TransformStream(); +stream.pipeTo(writable); +``` + +For your convenience `solid-js/web` exports an `isServer` flag. This is useful as most bundlers will be able to treeshake anything under this flag or imports only used by code under this flag out of your client bundle. + +```jsx +import { isServer } from "solid-js/web"; + +if (isServer) { + // only do this on the server +} else { + // only do this in the browser +} +``` + +## Hydration Script + +In order to progressively hydrate even before Solid's runtime loads, a special script needs to be inserted on the page. It can either be generated and inserted via `generateHydrationScript` or included as part of the JSX using the `` tag. + +```js +import { generateHydrationScript } from "solid-js/web"; + +const app = renderToString(() => ); + +const html = ` + + + 🔥 Solid SSR 🔥 + + + + ${generateHydrationScript()} + + ${app} + +`; +``` + +```jsx +import { HydrationScript } from "solid-js/web"; + +const App = () => { + return ( + + + 🔥 Solid SSR 🔥 + + + + + + {/*... rest of App*/} + + ); +}; +``` + +When hydrating from the document, inserting assets that aren't available in the client run can also mess things up when not under the `` tag. Solid provides a `` component whose children will work as normal on the server, but not hydrate in the browser. + +```jsx + + + +``` + +## Async and Streaming SSR + +These mechanisms are built on Solid's knowledge of how your application works. +It uses Suspense and the Resource API on the server, instead of fetching ahead and then rendering. +Solid fetches as it renders on the server just like it does on the client. +Your code is written exactly the same way. + +Async rendering waits until all Suspense boundaries resolve and then sends the results (or writes them to a file in the case of Static Site Generation). + +Streaming starts flushing synchronous content to the browser immediately. Initially, it renders your Suspense fallbacks on the server and sends them to the client. +Then, as the async data finishes loading on the server, we send the data and HTML over the same stream to the client. +The browser finishes the job, resolves the Suspense, and replaces the fallback with real content. + +The advantage of this approach: + +- Server doesn't have to wait for async data to respond. Assets can start loading sooner in the browser, and the user can start seeing content sooner. +- Compared to client fetching like JAMStack, data loading starts on the server immediately and doesn't have to wait for client JavaScript to load. +- All data is serialized and transported from server to client automatically. + +## SSR Caveats + +Solid's Isomorphic SSR solution is very powerful in that you can write your code mostly as single code base that runs similarly in both environments. However there are expectations that this puts on hydration. Mostly that the rendered view in the client is the same as it would be rendered on the server. It doesn't need to be exact in terms of text, but structurally the markup should be the same. + +We use markers rendered in the server to match elements and resource locations on server. For this reason the Client and Server should have the same components. This is not typically a problem given that Solid renders the same way on client and server. But currently there is no means to render something on the server that does not get hydrated on the client. Currently, there is no way to partially hydrate a whole page, and not generate hydration markers for it. It is all or nothing. Partial Hydration is something we want to explore in the future. + +Finally, all resources need to be defined under the `render` tree. They are automatically serialized and picked up in the browser, but that works because the `render` methods keep track of the progress of the render. Something we cannot do if they are created in isolated context. Similarly there is no reactivity on the server so do not update signals on initial render and expect them to reflect higher up the tree. While we have Suspense boundaries Solid's SSR is basically top down. + +## Getting Started with SSR + +SSR configurations are tricky. We have a few examples in the [solid-ssr](https://github.com/solidjs/solid/blob/main/packages/solid-ssr) package. + +However, a new starter is in the works [SolidStart](https://github.com/solidjs/solid-start) that aims to make this experience much smoother. + +## Getting Started with Static Site Generation + +[solid-ssr](https://github.com/solidjs/solid/blob/main/packages/solid-ssr) also ships with a utility for generating static or prerendered sites. Read the README for more information. diff --git a/langs/tr/guides/testing.md b/langs/tr/guides/testing.md new file mode 100644 index 00000000..03f3eca5 --- /dev/null +++ b/langs/tr/guides/testing.md @@ -0,0 +1,431 @@ +# Testing Solid + +To use your Solid code in production, it needs to be tested. Since you don't want to test everything manually, you need automated tests. This guide describes how to set everything up and a few useful patterns for testing Solid code. + +## Testing Setup + +We offer support for two test runners: + +- jest - very well established with many features + +- uvu - only brings the bare necessities + +Both are based around [solid-testing-library](https://github.com/solidjs/solid-testing-library), which integrates [Testing Library](https://testing-library.com/) into Solid. Testing Library mimics a light-weight browser and provides an API to interact with it from your tests. + +We maintain a starter template for Solid and Jest tests. We recommend you base your project on it, or alternatively install the starter template in a scratch project and copy the configuration from it into your own project. + +The templates use the [degit](https://github.com/Rich-Harris/degit) utility for installation. + +### Setting up Jest + +The Jest integration is based around the [solid-jest/preset/browser](https://github.com/solidjs/solid-jest) Jest configuration preset which lets you use Solid as in the browser. This uses babel to transform the Solid code. + +It uses [jest-dom](https://github.com/testing-library/jest-dom) to extend `expect` with a bunch of custom matchers that help you write tests. + +#### Jest with TypeScript (`ts-jest`) + +```bash +$ npx degit solidjs/templates/ts-jest my-solid-project +$ cd my-solid-project +$ npm install # or pnpm install or yarn install +``` + +Note that this template does not do typechecks during testing; you can use your IDE or a custom `tsc --noEmit` script in `package.json` to trigger such checks. + +### Setting up uvu + +We also maintain a starter template for `uvu`. + +It includes [solid-dom-testing](https://www.npmjs.com/package/solid-dom-testing) to help you write assertions useful with Testing Library. + +#### Uvu with TypeScript (`ts-uvu`) + +```bash +$ npx degit solidjs/templates/ts-uvu my-solid-project +$ cd my-solid-project +$ npm install # or pnpm install or yarn install +``` + +#### Uvu coverage Reports + +> Unfortunately, due to a [limitation of babel](https://github.com/babel/babel/issues/4289), we cannot get source maps output for transpiled JSX, which will result in components to show zero coverage. It will work for non-JSX code, though. + +If you want to check code coverage of your tests, the favorite tool for uvu is c8. To install and set it up, run: + +```sh +> npm i --save-dev c8 # or yarn add -D or pnpm +> npm set-script "test:coverage" "c8 uvu -r solid-register" +``` + +Now if you `npm run test:coverage`, you'll see the test coverage. + +If you want nice HTML coverage reports, you can use `c8 -r html` instead of `c8` to enable the html reporter. + +#### Watch Mode + +`uvu` does not have a watch mode out of the box, but you can use `chokidar-cli` to do the same: + +```sh +> npm i --save-dev chokidar-cli # or yarn add -D or pnpm +> npm set-script "test:watch" "chokidar src/**/*.ts src/**/*.tsx -c \"uvu -r solid-register\" +# use .js/.jsx instead of .ts/.tsx +``` + +Now if you run `npm run test:watch`, the tests will run every time you change a file. + +## Testing Patterns and Best Practices + +Now that you have installed your testing tools, you should start to use them. In order to make this easier, Solid supports a few nice patterns. + +### Testing Reactive State + +You may want to keep parts of your state separate from the components for ease of maintenance or being able to support multiple views. In this case, the interface against which you are testing is the state itself. Keep in mind that out of a [reactive root](https://www.solidjs.com/docs/latest/api#createroot) your state is not tracked and updates won't trigger effects and memos. + +Also, since effects trigger asynchronously, it can help to wrap our assertions in a final effect. Alternatively, to observe a sequence of effects over multiple changes, it can help to return the necessary tools from `createRoot` and execute them in an async test function (as `createRoot` itself cannot take an `async` function). + +As an example, let's test `createLocalStorage` from the [todo example](https://www.solidjs.com/examples/todos): + +```ts +import { createEffect } from "solid-js"; +import { createStore, Store, SetStoreFunction } from "solid-js/store"; + +export function createLocalStore( + initState: T +): [Store, SetStoreFunction] { + const [state, setState] = createStore(initState); + if (localStorage.todos) setState(JSON.parse(localStorage.todos)); + createEffect(() => (localStorage.todos = JSON.stringify(state))); + return [state, setState]; +} +``` + +Instead of creating a TODO component, we can test this model in isolation; when we do that, we need to keep in mind that 1. reactive changes only work when they have a tracking context provided by `render` or `createRoot` and 2. are asynchronous, but we can use `createEffect` to catch them. Using `createRoot` has the advantage that we can trigger the disposal manually: + +#### Testing with Jest + +```ts +import { createLocalStore } from "./main.tsx"; +import { createRoot, createEffect } from "solid-js"; + +describe("createLocalStore", () => { + beforeEach(() => { + localStorage.removeItem("todos"); + }); + + const initialState = { + todos: [], + newTitle: "", + }; + + test("it reads pre-existing state from localStorage", () => + createRoot((dispose) => { + const savedState = { todos: [], newTitle: "saved" }; + localStorage.setItem("todos", JSON.stringify(savedState)); + const [state] = createLocalStore(initialState); + expect(state).toEqual(savedState); + dispose(); + })); + + test("it stores new state to localStorage", () => + createRoot((dispose) => { + const [state, setState] = createLocalStore(initialState); + setState("newTitle", "updated"); + // to catch an effect, use an effect + return new Promise((resolve) => + createEffect(() => { + expect(JSON.parse(localStorage.todos || "")).toEqual({ + todos: [], + newTitle: "updated", + }); + dispose(); + resolve(); + }) + ); + })); + + test("it updates state multiple times", async () => { + const { dispose, setState } = createRoot((dispose) => { + const [state, setState] = createLocalStore(initialState); + return { dispose, setState }; + }); + setState("newTitle", "first"); + // wait a tick to resolve all effects + await new Promise((done) => setTimeout(done, 0)); + expect(JSON.parse(localStorage.todos || "")).toEqual({ + todos: [], + newTitle: "first", + }); + setState("newTitle", "second"); + await new Promise((done) => setTimeout(done, 0)); + expect(JSON.parse(localStorage.todos || "")).toEqual({ + todos: [], + newTitle: "first", + }); + dispose(); + }); +}); +``` + +#### Testing with uvu + +```ts +import { createLocalStore } from "./main"; +import { suite } from "uvu"; +import * as assert from "uvu/assert"; +import { createEffect, createRoot } from "solid-js"; + +const todoTest = suite("createLocalStore"); + +todoTest.before.each(() => { + localStorage.removeItem("todos"); +}); + +const initialState = { + todos: [], + newTitle: "", +}; + +todoTest("it reads pre-existing state from localStorage", () => + createRoot((dispose) => { + const savedState = { todos: [], newTitle: "saved" }; + localStorage.setItem("todos", JSON.stringify(savedState)); + const [state] = createLocalStore(initialState); + assert.equal(state, savedState); + dispose(); + }) +); + +todoTest("it stores new state to localStorage", () => + createRoot((dispose) => { + const [_, setState] = createLocalStore(initialState); + setState("newTitle", "updated"); + // to catch an effect, we need an effect + return new Promise((resolve) => + createEffect(() => { + assert.equal(JSON.parse(localStorage.todos || ""), { + todos: [], + newTitle: "updated", + }); + dispose(); + resolve(); + }) + ); + }) +); + +todoTest.run(); +``` + +### Testing directives + +[Directives](https://www.solidjs.com/docs/latest/api#use%3A___) allow using refs in a reusable way. They are basically functions that follow the pattern `(ref: HTMLElement, data: Accessor) => void`. In our [directives tutorial](https://www.solidjs.com/tutorial/bindings_directives?solved), we define the `clickOutside` directive that should call the callback wrapped in the accessor argument. + +We could now create a component and use the directive in there, but then we'd be testing the use of directives instead of directly testing the directive. It's simpler to test the surface of the directive by providing a mounted node and the accessor: + +#### Testing with Jest + +```ts +// click-outside.test.ts +import clickOutside from "click-outside"; +import { createRoot } from "solid-js"; +import { fireEvent } from "solid-testing-library"; + +describe("clickOutside", () => { + const ref = document.createElement("div"); + + beforeAll(() => { + document.body.appendChild(ref); + }); + + afterAll(() => { + document.body.removeChild(ref); + }); + + test("will trigger on click outside", () => + createRoot( + (dispose) => + new Promise((resolve) => { + let clickedOutside = false; + clickOutside(ref, () => () => { + clickedOutside = true; + }); + document.body.addEventListener("click", () => { + expect(clickedOutside).toBeTruthy(); + dispose(); + resolve(); + }); + fireEvent.click(document.body); + }) + )); + + test("will not trigger on click inside", () => + createRoot( + (dispose) => + new Promise((resolve) => { + let clickedOutside = false; + clickOutside(ref, () => () => { + clickedOutside = true; + }); + ref.addEventListener("click", () => { + expect(clickedOutside).toBeFalsy(); + dispose(); + resolve(); + }); + fireEvent.click(ref); + }) + )); +}); +``` + +#### Testing with uvu + +```ts +// click-outside.test.ts +import clickOutside from "click-outside.tsx"; +import { createRoot } from "solid-js"; +import { fireEvent } from "solid-testing-library"; + +const clickTest = suite("clickOutside"); + +const ref = document.createElement("div"); + +clickTest.before(() => { + document.body.appendChild(ref); +}); + +clickTest.after(() => { + document.body.removeChild(ref); +}); + +clickTest("will trigger on click outside", () => + createRoot( + (dispose) => + new Promise((resolve) => { + let clickedOutside = false; + clickOutside(ref, () => () => { + clickedOutside = true; + }); + document.body.addEventListener("click", () => { + assert.ok(clickedOutside); + dispose(); + resolve(); + }); + fireEvent.click(document.body); + }) + ) +); + +clickTest("will not trigger on click inside", () => + createRoot( + (dispose) => + new Promise((resolve) => { + let clickedOutside = false; + clickOutside(ref, () => () => { + clickedOutside = true; + }); + ref.addEventListener("click", () => { + assert.is(clickedOutside, false); + dispose(); + resolve(); + }); + fireEvent.click(ref); + }) + ) +); + +clickTest.run(); +``` + +### Testing components + +Let's take a simple click-counter component that we want to test: + +```ts +// main.tsx +import { createSignal, Component } from "solid-js"; + +export const Counter: Component = () => { + const [count, setCount] = createSignal(0); + + return ( +
    setCount((c) => c + 1)}> + Count: {count()} +
    + ); +}; +``` + +Here we use `solid-testing-library`. It's most important helpers are `render` to render a component to the DOM in a managed way, `fireEvent` to dispatch events in a way that resembles actual user events and `screen` to provide global selectors. We also use helpful assertions added to `expect` provided by `@testing-library/jest-dom`. + +#### Testing with Jest + +```ts +// main.test.tsx +import { Counter } from "./main"; +import { cleanup, fireEvent, render, screen } from "solid-testing-library"; + +describe("Counter", () => { + afterEach(cleanup); + + test("it starts with zero", () => { + render(() => ); + const button = screen.getByRole("button"); + expect(button).toBeInTheDocument(); + expect(button).toHaveTextContent("Count: 0"); + }); + + test("it increases its value on click", async () => { + render(() => ); + const button = screen.getByRole("button"); + fireEvent.click(button); + // the event loop takes one Promise to resolve to be finished + await Promise.resolve(); + expect(button).toHaveTextContent("Count: 1"); + fireEvent.click(button); + await Promise.resolve(); + expect(button).toHaveTextContent("Count: 2"); + }); +}); +``` + +#### Testing with uvu + +```ts +// main.test.tsx +import { suite } from "uvu"; +import * as assert from "uvu/assert"; +import { Counter } from "main"; +import { fireEvent, render, screen } from "solid-testing-library"; +import { isInDocument, hasTextContent } from "solid-dom-testing"; + +const testCounter = suite("Counter"); + +testCounter.after.each(cleanup); + +testCounter("it starts with zero", () => { + const { getByRole } = render(() => ); + const button = getByRole("button"); + assert.ok(isInDocument(button), "button not in dom"); + assert.ok(hasTextContent(button, "Count: 0"), "wrong text content"); +}); + +testCounter("it increases its value on click", async () => { + render(() => ); + const button = screen.getByRole("button"); + fireEvent.click(button); + // the event loop takes one Promise to resolve to be finished + await Promise.resolve(); + assert.ok( + hasTextContent(button, "Count: 1"), + "not count 1 after first click" + ); + fireEvent.click(button); + await Promise.resolve(); + assert.ok( + hasTextContent(button, "Count: 2"), + "not count 2 after first click" + ); +}); + +testCounter.run(); +``` diff --git a/langs/tr/guides/typescript.md b/langs/tr/guides/typescript.md new file mode 100644 index 00000000..69324683 --- /dev/null +++ b/langs/tr/guides/typescript.md @@ -0,0 +1,632 @@ +# TypeScript + +Solid is designed to be easy to use with TypeScript: +its use of standard JSX makes code largely understood by TypeScript, +and it provides sophisticated built-in types for its API. +This guide covers some useful tips for working with TypeScript and +typing your Solid code. + +## Configuring TypeScript + +The [Solid starter templates](https://github.com/solidjs/templates/) +offer good starting points for +[`tsconfig.json`](https://github.com/solidjs/templates/blob/master/ts/tsconfig.json). + +Most importantly, to use TypeScript with the Solid JSX compiler, +you need to configure TypeScript to leave JSX constructs alone via +[`"jsx": "preserve"`](https://www.typescriptlang.org/tsconfig#jsx), +and tell TypeScript where the JSX types come from via +[`"jsxImportSource": "solid-js"`](https://www.typescriptlang.org/tsconfig#jsxImportSource). +So, a minimal `tsconfig.json` would look like this: + +```json +{ + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + } +} +``` + +If your code base uses a mix of JSX types (e.g., some files are React +while other files are Solid), you can set the default `jsxImportSource` +in `tsconfig.json` for the majority of your code, and then +[override the `jsxImportSource` option](https://www.typescriptlang.org/tsconfig#jsxImportSource) +in specific `.tsx` files using the following pragma: + +```ts +/** @jsxImportSource solid-js */ +``` + +or + +```ts +/** @jsxImportSource react */ +``` + +## API Types + +Solid is written in TypeScript, so everything is typed out of the box. +The [API documentation](https://www.solidjs.com/docs/latest/api) details the +types for all API calls, as well as several helpful type definitions to make it +easier to refer to Solid notions when you need to specify explicit types. +Here, we explore the resulting types when using a few core primitives. + +### Signals + +`createSignal` is parameterized by the type `T` of the object stored in the +signal. For example: + +```ts +const [count, setCount] = createSignal(); +``` + +The first `createSignal` has return type `Signal`, corresponding to +the type we passed to it. This is a tuple of the getter and +setter, which each have a generic type: + +```ts +import type { Signal, Accessor, Setter } from 'solid-js'; +type Signal = [get: Accessor, set: Setter]; +``` + +In this case, the signal getter `count` has type +`Accessor`. `Accessor` is a type definition +provided by Solid, in this case equivalent to `() => number | undefined`. +The `| undefined` gets added in this example because we did not provide a +default value to `createSignal`, so the signal value indeed starts out as +`undefined`. + +The signal setter `setCount` has type `Setter`, which is a more +complicated type definition corresponding roughly to +`(value?: number | ((prev?: number) => number)) => number`, representing the +two possibilities for the passed argument: you can call `setCount` with +either a `number` or a +function taking the previous value (if there was one) and returning a `number`. + +The actual `Setter` type is more complicated, to detect accidentally passing +a function to the setter when you might have wanted to set the signal to that +function value instead of calling the function to determine the new value. +If you're getting a TypeScript error "Argument ... is not assignable to +parameter" when calling `setCount(value)`, then try wrapping the setter +argument as in `setCount(() => value)` to make sure that `value` isn't called. + +##### Defaults + +We can avoid having to explicitly provide the type of the signal when calling +`createSignal`, and avoid the `| undefined` part of the type, by providing +a default value to `createSignal`: + +```ts +const [count, setCount] = createSignal(0); +const [name, setName] = createSignal(''); +``` + +In this case, TypeScript infers that the signal types are `number` and `string` +respectively. Thus, for example, `count` obtains type `Accessor` +and `name` obtains type `Accessor` (without `| undefined`). + +### Context + +Similar to signals, +[`createContext`](https://www.solidjs.com/docs/latest/api#createcontext) +is parameterized by the type `T` of the context value. +We can provide this type explicitly: + +```ts +type Data = {count: number, name: string}; +const dataContext = createContext(); +``` + +In this case, `dataContext` has type `Context`, +causing `useContext(dataContext)` to have matching return type `Data | +undefined`. +The reason for `| undefined` is that the context might not be provided in the +ancestors of the current component, in which case `useContext` returns +`undefined`. + +If we instead provide a default value to `createContext`, we avoid the +`| undefined` part of the type, and often avoid having to explicitly specify +the type of the `createContext` as well: + +```ts +const dataContext = createContext({count: 0, name: ''}); +``` + +In this case, TypeScript infers that `dataContext` has type +`Context<{count: number, name: string}>`, which is equivalent to +`Context` (without `| undefined`). + +Another common pattern is to define a factory function that produces the +value for a context. Then we can grab the return type of that function using +TypeScript's +[`ReturnType`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) +type helper, and use that to type the context: + +```ts +export const makeCountNameContext = (initialCount = 0, initialName = '') => { + const [count, setCount] = createSignal(initialCount); + const [name, setName] = createSignal(initialName); + return [{count, name}, {setCount, setName}] as const; + // `as const` forces tuple type inference +}; +type CountNameContextType = ReturnType; +export const CountNameContext = createContext(); +export const useCountNameContext = () => useContext(CountNameContext); +``` + +In this example, `CountNameContextType` corresponds to the return value of +`makeCountNameContext`: +```ts +[ + {readonly count: Accessor, readonly name: Accessor}, + {readonly setCount: Setter, readonly setName: Setter} +] +``` + +and `useCountNameContext` has type `() => CountNameContextType | undefined`. + +If you want to avoid the `undefined` possibility, you could assert that the +context is always provided when used: +```ts +export const useCountNameContext = () => useContext(CountNameContext)!; +``` + +This is a dangerous assumption; it would be safer to actually provide a +default argument to `createContext` so that the context is always +defined. + +## Component Types + +```ts +import type { JSX, Component } from 'solid-js'; +type Component

    = (props: P) => JSX.Element; +``` + +To type a basic component function, use the `Component

    ` type, +where `P` is the type of the `props` argument and should be an [object type](https://www.typescriptlang.org/docs/handbook/2/objects.html). +This will enforce that correctly typed props get passed in as attributes, +and that the return value is something that can be rendered by Solid: +a `JSX.Element` can be a DOM node, an array of `JSX.Element`s, +a function returning a `JSX.Element`, a boolean, `undefined`/`null`, etc. +Here are some examples: + +```tsx +const Counter: Component = () => { + const [count, setCount] = createSignal(0); + return ( + + ); +}; + +; // good +; // type error: no initial prop +hi // type error: no children prop + +const InitCounter: Component<{initial: number}> = (props) => { + const [count, setCount] = createSignal(props.initial); + return ( + + ); +}; + +; // good +``` + +If you want your component to take JSX children, you can either explicitly +add a type for `children` to `P`, or you can use the `ParentComponent` type +which automatically adds `children?: JSX.Element`. Alternatively, if you'd +like to declare your component with `function` instead of `const`, you can +use the `ParentProps` helper to type `props`. Some examples: + +```tsx +import { JSX, ParentComponent, ParentProps } from 'solid-js'; +type ParentProps

    = P & { children?: JSX.Element }; +type ParentComponent

    = Component>; + +// Equivalent typings: +//const CustomCounter: Component<{children?: JSX.Element}> = ... +//function CustomCounter(props: ParentProps): JSX.Element { ... +const CustomCounter: ParentComponent = (props) => { + const [count, setCount] = createSignal(0); + return ( + + ); +}; + +// Equivalent typings: +//const CustomInitCounter: Component<{initial: number, children?: JSX.Element}> = ... +//function CustomInitCounter(props: ParentProps<{initial: number}>): JSX.Element { ... +const CustomInitCounter: ParentComponent<{initial: number}> = (props) => { + const [count, setCount] = createSignal(props.initial); + return ( + + ); +}; +``` + +In the latter example, the `props` parameter automatically gets typed as +`props: ParentProps<{initial: number}>` which is equivalent to +`props: {initial: number, children?: JSX.Element}`. +(Note that, before Solid 1.4, `Component` was equivalent to `ParentComponent`.) + +Solid provides two other `Component` subtypes for dealing with `children`: + +```ts +import {JSX, FlowComponent, FlowProps, VoidComponent, VoidProps} from 'solid-js'; +type FlowProps

    = P & { children: C }; +type FlowComponent

    = Component>; +type VoidProps

    = P & { children?: never }; +type VoidComponent

    = Component>; +``` + +`VoidComponent` is for components that definitely do not support `children`. +`VoidComponent

    ` is equivalent to `Component

    ` when `P` doesn't provide +a type for `children`. + +`FlowComponent` is intended for "control flow" components like Solid's +`` and ``. Such components generally require `children` to make +sense, and sometimes have specific types for `children`, such as requiring it +to be a single function. For example: + +```tsx +const CallMeMaybe: FlowComponent<{when: boolean}, () => void> = (props) => { + createEffect(() => { + if (props.when) + props.children(); + }); + return <>{props.when ? 'Calling' : 'Not Calling'}; +}; + +; // type error: missing children +hi; // type error: children + + {() => console.log("Here's my number")} +; // good +``` + +## Event Handlers + +The namespace `JSX` offers a suite of useful types for working with HTML DOM +in particular. See the +[definition of JSX in dom-expressions](https://github.com/ryansolid/dom-expressions/blob/main/packages/dom-expressions/src/jsx.d.ts) +for all the types provided. + +One useful helper type provided by the `JSX` namespace is +`JSX.EventHandler`, +which represents a single-argument event handler for a DOM element type `T` +and event type `E`. +You can use this to type any event handlers you define outside JSX. +For example: + +```tsx +import type { JSX } from 'solid-js'; +const onInput: JSX.EventHandler = (event) => { + console.log('input changed to', event.currentTarget.value); +}; + + +``` + +Handlers defined inline within +[`on___` JSX attributes](https://www.solidjs.com/docs/latest/api#on___) +(with built-in event types) are automatically typed as the appropriate +`JSX.EventHandler`: + +```tsx + { + console.log('input changed to', event.currentTarget.value); +}}/>; +``` + +Note that `JSX.EventHandler` constrains the event's +[`currentTarget` attribute](https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget) +to be of type `T` (in the example, `event.currentTarget` is typed +as `HTMLInputEvent`, so has attribute `value`). However, the event's +[`target` attribute](https://developer.mozilla.org/en-US/docs/Web/API/Event/target) +could be any `DOMElement`. +This is because `currentTarget` is the element that the +event handler was attached to, so has a known type, whereas `target` is +whatever the user interacted with that caused the event to bubble to or get +captured by the event handler, which can be any DOM element. + +## The ref Attribute + +When we use the `ref` attribute with a variable, we tell Solid to assign the +DOM element to +the variable once the element is rendered. Without TypeScript, this looks like: + +```jsx +let divRef; + +console.log(divRef); // undefined + +onMount(() => { + console.log(divRef); //

    element +}) + +return ( +
    +) +``` + +This presents a challenge for typing that variable: should we type `divRef` +as an `HTMLDivElement`, even though it's only set as such after rendering? +(Here we assume TypeScript's `strictNullChecks` mode is turned on; +otherwise, TypeScript ignores potentially `undefined` variables.) + +The safest pattern in TypeScript is to acknowledge that `divRef` is `undefined` +for a period of time, and check when using it: + +```tsx +let divRef: HTMLDivElement | undefined; + +divRef.focus(); // correctly reported as an error at compile time + +onMount(() => { + if (!divRef) return; + divRef.focus(); // correctly allowed +}); + +return ( +
    + ... +
    +); +``` + +Alternatively, because we know `onMount` gets called only after the `
    ` +element gets rendered, we could use a +[non-null assertion (`!`)](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#non-null-assertion-operator-postfix-) +when accessing `divRef` within `onMount`: + +```tsx +onMount(() => { + divRef!.focus(); +}); +``` + +Another fairly safe pattern is to omit `undefined` from `divRef`'s type, +and use a +[definite assignment assertion (`!`)](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions) +in the `ref` attribute: + +```tsx +let divRef: HTMLDivElement; + +divRef.focus(); // correctly reported as an error at compile time + +onMount(() => { + divRef.focus(); // correctly allowed +}); + +return ( +
    + ... +
    +); +``` + +We need to use `ref={divRef!}` because TypeScript assumes that the `ref` +attribute is being set to the `divRef` variable, and thus `divRef` should +already be assigned. In Solid, it's the other way around: `divRef` gets +assigned to by the `ref` attribute. The definite assignment assertion +`divRef!` effectively convinces TypeScript that this is what's happening: +TypeScript will understand that `divRef` has been assigned after this line. + +With this pattern, TypeScript will correctly flag any accidental uses of +refs inside the body of the function (before the JSX block where they get +defined). However, TypeScript currently does not flag use of potentially +undefined variables within nested functions. In the context of Solid, +you need to take care not to use refs inside `createMemo`, `createRenderEffect`, +and `createComputed` (before the JSX block that defines the refs), +because those functions are called immediately, +so the refs won't be defined yet (yet TypeScript won't flag this as an error). +By contrast, the previous pattern would catch these errors. + +Another common, but less safe, pattern is to put the definite assignment +assertion at the point of variable declaration. + +```tsx +let divRef!: HTMLDivElement; + +divRef.focus(); // allowed despite causing an error + +onMount(() => { + divRef.focus(); // correctly allowed +}); + +return ( +
    + ... +
    +); +``` + +This approach effectively turns off assignment checking for that variable, +which is an easy workaround, but requires additional care. +In particular, unlike the previous pattern, it incorrectly allows premature +use of the variable, even outside nested functions. + +## Control Flow Narrowing + +A common pattern is to use +[``](https://www.solidjs.com/docs/latest/api#%3Cshow%3E) +to display data only when that data is defined: + +```tsx +const [name, setName] = createSignal(); + +return ( + + Hello {name().replace(/\s+/g, '\xa0')}! + +); +``` + +In this case, TypeScript can't determine that the two calls to `name()` will +return the same value, and that the second call will happen only if the first +call returned a truthy value. Thus it will complain that `name()` might be +`undefined` when trying to call `.replace()`. + +Here are two workarounds for this issue: + +1. You can manually assert that `name()` will be non-null in the second call + using TypeScript's + [non-null assertion operator `!`](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#non-null-assertion-operator-postfix-): + + ```tsx + return ( + + Hello {name()!.replace(/\s+/g, '\xa0')}! + + ); + ``` + +2. You can use the callback form of ``, which passes in the value of the + `when` prop when it is truthy: + + ```tsx + return ( + + {(n) => + <>Hello {n.replace(/\s+/g, '\xa0')}! + } + + ); + ``` + + In this case, the typing of the `Show` component is clever enough to tell + TypeScript that `n` is truthy, so it can't be `undefined` (or `null` or + `false`). + + Note, however, that this form of `` forces the entirety of the + children to render + from scratch every time `name()` changes, instead of doing this just when `name()` changes from a falsy to a truthy value. + This means that the children don't have the full benefits of fine-grained + reactivity (re-using unchanged parts and updating just what changed). + +## Special JSX Attributes and Directives + +### `on:___`/`oncapture:___` + +If you use custom event handlers via Solid's +[`on:___`/`oncapture:___` attributes](https://www.solidjs.com/docs/latest/api#on%3A___%2Foncapture%3A___), +you should define corresponding types for the resulting `Event` objects +by overriding the `CustomEvents` and `CustomCaptureEvents` interfaces +within module `"solid-js"`'s `JSX` namespace, like so: + +```tsx +class NameEvent extends CustomEvent { + type: 'Name'; + detail: {name: string}; + + constructor(name: string) { + super('Name', {detail: {name}}); + } +} + +declare module "solid-js" { + namespace JSX { + interface CustomEvents { // on:Name + "Name": NameEvent; + } + interface CustomCaptureEvents { // oncapture:Name + "Name": NameEvent; + } + } +} + +
    console.log('name is', event.detail.name)}/> +``` + +### `prop:___`/`attr:___` + +If you use forced properties via Solid's +[`prop:___` attributes](https://www.solidjs.com/docs/latest/api#prop%3A___), +or custom attributes via Solid's +[`attr:___` attributes](https://www.solidjs.com/docs/latest/api#attr%3A___), +you can define their types in the `ExplicitProperties` and +`ExplicitAttributes` interfaces, respectively: + +```tsx +declare module "solid-js" { + namespace JSX { + interface ExplicitProperties { // prop:___ + count: number; + name: string; + } + interface ExplicitAttributes { // attr:___ + count: number; + name: string; + } + } +} + + + +``` + +### `use:___` + +If you define custom directives for Solid's +[`use:___` attributes](https://www.solidjs.com/docs/latest/api#use%3A___), +you can type them in the `Directives` interface, like so: + +```tsx +function model(element: HTMLInputElement, value: Accessor>) { + const [field, setField] = value(); + createRenderEffect(() => (element.value = field())); + element.addEventListener("input", (e) => setField(e.target.value)); +} + +declare module "solid-js" { + namespace JSX { + interface Directives { // use:model + model: Signal; + } + } +} + +let [name, setName] = createSignal(''); + +; +``` + +If you're `import`ing a directive `d` from another module, and `d` is used only +as a directive `use:d`, then TypeScript (or more precisely, +[`babel-preset-typescript`](https://babeljs.io/docs/en/babel-preset-typescript)) +will by default remove the `import` of `d` (for fear that `d` is a type, +as TypeScript doesn't understand `use:d` as a reference to `d`). +There are two ways around this issue: + +1. Use + [`babel-preset-typescript`'s `onlyRemoveTypeImports: true`](https://babeljs.io/docs/en/babel-preset-typescript#onlyremovetypeimports) + configuration option, + which prevents it from removing any `import`s except for `import type ...`. + If you're using `vite-plugin-solid`, you can specify this option via + `solidPlugin({ typescript: { onlyRemoveTypeImports: true } })` + in `vite.config.ts`. + + Note that this option can be problematic if you don't vigilantly use + `export type` and `import type` throughout your codebase. + +2. Add a fake access like `false && d;` to every module `import`ing + directive `d`. + This will stop TypeScript from removing the `import` of `d`, and assuming + you're tree-shaking via e.g. [Terser](https://terser.org/), + this code will be omitted from your final code bundle. + + The simpler fake access `d;` will also prevent the `import` from being + removed, but will typically not be tree-shaken away, so will end up in + your final code bundle. diff --git a/langs/tr/tutorials/async_lazy/lesson.json b/langs/tr/tutorials/async_lazy/lesson.json new file mode 100644 index 00000000..de56f031 --- /dev/null +++ b/langs/tr/tutorials/async_lazy/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { lazy } from \"solid-js\";\n\nimport Greeting from \"./greeting\"\n\nfunction App() {\n return (\n <>\n

    Welcome

    \n \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "greeting", + "content": "export default function Greeting(props) {\n return

    Hi, {props.name}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/async_lazy/lesson.md b/langs/tr/tutorials/async_lazy/lesson.md new file mode 100644 index 00000000..d23ac4a0 --- /dev/null +++ b/langs/tr/tutorials/async_lazy/lesson.md @@ -0,0 +1,20 @@ +Bütün bundler'lar (Webpack, Rollup, Parcel, Vite vb.) dinamik import'lar kullandığından, kod bölme (code splitting) işlemini otomatik olarak gerçekleştirirler. Solid'in içerisindeki `lazy` metodu, ertelenmiş lazy yükleme için, bileşenin dinamik import'unu wrap etmenizi sağlar. Çıktı, JSX'te normal bir şekilde kullanılabilen bir bileşenden farksızdır ancak tek fark `lazy` ile oluşturulan import ilk kez render edildiğinde, import ettiği kodu dinamik olarak yükler ve kod elde edilene kadar o render kolunu durdurur. + +`lazy` kullanmak için aşağıdaki satırı: +```js +import Greeting from "./greeting"; +``` +Aşağıdaki ile değiştirelim: +```js +const Greeting = lazy(() => import("./greeting")); +``` + +İşlem büyük olasılıkla hala gözle fark edilemeyecek kadar hızlı olacaktır, eğer yüklenmeyi görmek isterseniz bir miktar sahte gecikme ekleyebilirsiniz. + +```js +const Greeting = lazy(async () => { + // simulate delay + await new Promise(r => setTimeout(r, 1000)) + return import("./greeting") +}); +``` diff --git a/langs/tr/tutorials/async_lazy/solved.json b/langs/tr/tutorials/async_lazy/solved.json new file mode 100644 index 00000000..c61a2066 --- /dev/null +++ b/langs/tr/tutorials/async_lazy/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { lazy } from \"solid-js\";\n\nconst Greeting = lazy(() => import(\"./greeting\"));\n\nfunction App() {\n return (\n <>\n

    Welcome

    \n \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "greeting", + "content": "export default function Greeting(props) {\n return

    Hi, {props.name}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/async_resources/lesson.json b/langs/tr/tutorials/async_resources/lesson.json new file mode 100644 index 00000000..445c1b28 --- /dev/null +++ b/langs/tr/tutorials/async_resources/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { createSignal, createResource } from \"solid-js\";\nimport { render } from \"solid-js/web\";\n\nconst fetchUser = async (id) =>\n (await fetch(`https://swapi.dev/api/people/${id}/`)).json();\n\nconst App = () => {\n const [userId, setUserId] = createSignal();\n const [user] = createSignal();\n\n return (\n <>\n setUserId(e.currentTarget.value)}\n />\n {user.loading && \"Loading...\"}\n
    \n
    {JSON.stringify(user(), null, 2)}
    \n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/async_resources/lesson.md b/langs/tr/tutorials/async_resources/lesson.md new file mode 100644 index 00000000..627b69f0 --- /dev/null +++ b/langs/tr/tutorials/async_resources/lesson.md @@ -0,0 +1,19 @@ +Resource'lar özellikle Async yüklemeyi işlemek için tasarlanmış özel Sinyallerdir. Amaçları, asenkron değerleri Sold'in dağıtık yürütme modelinde etkileşime girmelerini kolaylaştıracak şekilde sarmaktır. Bu sıralı modeller sağlayan async/await veya generator'ların tam tersidir. Amacı async'in akışı engellemesinin önüne geçmektir. + +Resource'lar, bir promise döndüren async data fetcher fonksiyonuna sorgu sağlayan bir kaynak sinyali tarafından yönlendirilebilir. Fetcher fonksiyonun ne olduğu önemli değildir, yani tipik REST endpoint'ine veya GraphQL'e ya da bir promise üreten herhangi bir şeye ulaşmakta kullanılabilir. Resource'lar verilerin yüklenmesi konusunda bilgi sahibi değillerdir yani promise'e bağlı çalışır ve onun tarafından yönlendirilirler. + +Ortaya çıkan Resource sinyali, mevcut duruma göre görüntüyü kontrol etmemizi sağlayan reaktif `loading` ve `error` property'lerini de içerir. + +Örneğimizde user sinyalini Resource ile değiştirelim: +```js +const [user] = createResource(userId, fetchUser); +``` +Ürettiğimiz user, `userId` sinyali tarafından yönetilir ve değişiklik olduğu zaman fetch metodunu çalıştırır, bu kadar. + +`createResource`'tan dönen ikinci değer, içerideki Signal'i doğrudan güncellemek için bir `mutate` metodu ve kaynak değişmemiş olsa bile mevcut sorguyu yeniden yüklemek için bir `refetch` metodu içerir. + +```js +const [user, { mutate, refetch }] = createResource(userId, fetchUser); +``` + +`lazy` içeride `createResource` kullanarak dinamik import'ları yönetir. diff --git a/langs/tr/tutorials/async_resources/solved.json b/langs/tr/tutorials/async_resources/solved.json new file mode 100644 index 00000000..e37ab753 --- /dev/null +++ b/langs/tr/tutorials/async_resources/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { createSignal, createResource } from \"solid-js\";\nimport { render } from \"solid-js/web\";\n\nconst fetchUser = async (id) =>\n (await fetch(`https://swapi.dev/api/people/${id}/`)).json();\n\nconst App = () => {\n const [userId, setUserId] = createSignal();\n const [user] = createResource(userId, fetchUser);\n\n return (\n <>\n setUserId(e.currentTarget.value)}\n />\n {user.loading && \"Loading...\"}\n
    \n
    {JSON.stringify(user(), null, 2)}
    \n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/async_suspense/lesson.json b/langs/tr/tutorials/async_suspense/lesson.json new file mode 100644 index 00000000..6779e6fb --- /dev/null +++ b/langs/tr/tutorials/async_suspense/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { lazy, Suspense } from \"solid-js\";\n\nconst Greeting = lazy(async () => {\n // simulate delay\n await new Promise(r => setTimeout(r, 1000))\n return import(\"./greeting\")\n});\n\nfunction App() {\n return (\n <>\n

    Welcome

    \n \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "greeting", + "content": "export default function Greeting(props) {\n return

    Hi, {props.name}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/async_suspense/lesson.md b/langs/tr/tutorials/async_suspense/lesson.md new file mode 100644 index 00000000..1152ce95 --- /dev/null +++ b/langs/tr/tutorials/async_suspense/lesson.md @@ -0,0 +1,31 @@ +`lazy` ve `createResource` kendi başlarına kullanılabilseler de Solid, birden fazla asenkron event'in görüntülenmesini koordine etmek için bir mekanizma da sağlar. `Suspense`, bu asenkron event'ler çözüldükçe kısmen yüklenen içerik yerine yedek bir placeholder tutan bir sınır görevi görür. + +Bu şekilde, çok fazla ara ve kısmi yükleme durumlarının neden olduğu problemleri düzenleyerek kullanıcı deneyimini iyileştirebiliriz. `Suspense` kendisinden sonra gelen asenkron okumaları otomatik olarak algılayıp buna göre hareket eder. İstediğiniz kadar `Suspense` bileşenini iç içe yerleştirebilirsiniz, bu durumda yükleme durumu algılandığında yalnızca en yakın ancestor fallback'ine dönüş yapılacaktır. + +Lazy load örneğimize bir `Suspense` bileşeni ekleyelim: + +```jsx +<> +

    Welcome

    + Loading...

    }> + +
    + +``` + +Artık yükleme durumu için bir placeholder'ımız var. + +Asenkron fetching'in kendisinin değil de asenkron olarak türemiş bir değerin okunmasının `Suspense`'i tetiklendiğine dikkat etmelisiniz. Eğer bir kaynak sinyali (`lazy` olsa bile) `Suspense` boundary'si altında okunmazsa, suspense işlemi gerçekleşmeyecektir. + +`Suspense` birçok açıdan her iki branch'i de render eden bir `Show` bileşenidir. Asenkron Sunucu render işlemleri için `Suspense` hayati öneme sahip olsa da, client'ta render edilecek kod için hemen `Suspense` kullanma ihtiyacı hissetmeyin. Solid'in render sisteminin işleri manuel olarak bölmek için ek bir maliyeti yoktur. + +```jsx +function Deferred(props) { + const [resume, setResume] = createSignal(false); + setTimeout(() => setResume(true), 0); + + return {props.children}; +} +``` + +Solid'de tüm işlemler bağımsız olarak sıralanır. Time Slicing gibi ek işlere gerek yoktur. diff --git a/langs/tr/tutorials/async_suspense/solved.json b/langs/tr/tutorials/async_suspense/solved.json new file mode 100644 index 00000000..c43b56f0 --- /dev/null +++ b/langs/tr/tutorials/async_suspense/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { lazy, Suspense } from \"solid-js\";\n\nconst Greeting = lazy(async () => {\n // simulate delay\n await new Promise(r => setTimeout(r, 1000))\n return import(\"./greeting\")\n});\n\nfunction App() {\n return (\n <>\n

    Welcome

    \n Loading...

    }>\n \n
    \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "greeting", + "content": "export default function Greeting(props) {\n return

    Hi, {props.name}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/async_suspense_list/lesson.json b/langs/tr/tutorials/async_suspense_list/lesson.json new file mode 100644 index 00000000..a627b09a --- /dev/null +++ b/langs/tr/tutorials/async_suspense_list/lesson.json @@ -0,0 +1,16 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { Suspense } from \"solid-js\";\n\nimport fetchProfileData from \"./mock-api\";\nimport ProfilePage from \"./profile\";\n\nconst App = () => {\n const { user, posts, trivia } = fetchProfileData();\n return (\n Loading...}>\n \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + }, + { + "name": "profile", + "content": "import { For, Suspense, SuspenseList } from \"solid-js\";\n\nconst ProfileDetails = (props) =>

    {props.user?.name}

    ;\n\nconst ProfileTimeline = (props) => (\n
      \n {(post) =>
    • {post.text}
    • }
      \n
    \n);\n\nconst ProfileTrivia = (props) => (\n <>\n

    Fun Facts

    \n
      \n {(fact) =>
    • {fact.text}
    • }
      \n
    \n \n);\n\nconst ProfilePage = (props) => (\n <>\n \n Loading posts...}>\n \n \n Loading fun facts...}>\n \n \n \n);\n\nexport default ProfilePage;" + }, + { + "name": "mock-api", + "content": "import { createResource } from \"solid-js\";\n\nexport default function fetchProfileData() {\n const [user] = createResource(fetchUser);\n const [posts] = createResource(fetchPosts);\n const [trivia] = createResource(fetchTrivia);\n return { user, posts, trivia };\n}\n\nfunction fetchUser() {\n console.log(\"fetch user...\");\n return new Promise((resolve) => {\n setTimeout(() => {\n console.log(\"fetched user\");\n resolve({\n name: \"Ringo Starr\"\n });\n }, 500);\n });\n}\n\nlet ringoPosts = [\n {\n id: 0,\n text: \"I get by with a little help from my friends\"\n },\n {\n id: 1,\n text: \"I'd like to be under the sea in an octupus's garden\"\n },\n {\n id: 2,\n text: \"You got that sand all over your feet\"\n }\n];\n\nfunction fetchPosts() {\n let ringoPostsAtTheTime = ringoPosts;\n console.log(\"fetch posts...\");\n return new Promise((resolve) => {\n setTimeout(() => {\n console.log(\"fetched posts\");\n resolve(ringoPostsAtTheTime);\n }, 3000 * Math.random());\n });\n}\n\nfunction fetchTrivia() {\n console.log(\"fetch trivia...\");\n return new Promise((resolve) => {\n setTimeout(() => {\n console.log(\"fetched trivia\");\n resolve([\n {\n id: 1,\n text:\n 'The nickname \"Ringo\" came from his habit of wearing numerous rings.'\n },\n {\n id: 2,\n text: \"Plays the drums left-handed with a right-handed drum set.\"\n },\n {\n id: 3,\n text: \"Nominated for one Daytime Emmy Award, but did not win\"\n }\n ]);\n }, 3000 * Math.random());\n });\n}\n" + } + ] +} diff --git a/langs/tr/tutorials/async_suspense_list/lesson.md b/langs/tr/tutorials/async_suspense_list/lesson.md new file mode 100644 index 00000000..2ae2409f --- /dev/null +++ b/langs/tr/tutorials/async_suspense_list/lesson.md @@ -0,0 +1,17 @@ +Bazen, koordine etmek istediğimiz birden fazla `Suspense` bileşenimiz olabilir. Olası yaklaşımlardan birisi, her şeyi tek bir `Suspense` altında toplamaktır, fakat bu bizi tek bir yükleme davranışı ile sınırlar. Tek bir geri dönüş durumu, her şeyin, her zaman, son şey yüklenene kadar beklemesi gerektiği anlamına gelir. Bunun yerine Solid bunu koordine etmek için `SuspenseList` bileşenini sunar. + +Örneğimizdeki gibi birden fazla `Suspense` bileşenine sahip olduğunuzu düşünün. Bunları, `revealOrder` ve `forwards` ile yapılandırılmış bir `SuspenseList` ile sararsak, yüklenme sıralarına bakılmaksızın ağaçta göründükleri sırada oluşturulurlar. Bu sayfadaki ileri geri hareketi azaltır. `revealOrder`, `backward` veya `together` değerleri ile ayarlanabilir, bu da sırasıyla sırayı tersine çevirir veya tüm `Suspense` bileşenlerinin yüklenmesini bekler. Ayrıca, `hidden` veya `collapsed` olarak ayarlanabilen bir `tail` seçeneği vardır. Bu, tüm geri dönüşleri gösterme varsayılan davranışını ya hiçbirini göstermeyerek ya da `revealOrder` tarafından belirlenen yönde bir sonrakini gösterecek şekilde geçersiz kılar. + +Örneğimiz şu anda placeholder'ların yüklenmesi açısından biraz karışık durumda. Tüm veriler bağımsız olarak yüklenirken verilerin yüklenme sırasına bağlı olarak genellikle birden fazla placeholder gösteriyoruz. `ProfilePage` bileşenimizin JSX'ini bir `` ile saralım. + +```jsx + + + Loading posts...}> + + + Loading fun facts...}> + + + +``` diff --git a/langs/tr/tutorials/async_suspense_list/solved.json b/langs/tr/tutorials/async_suspense_list/solved.json new file mode 100644 index 00000000..4df03067 --- /dev/null +++ b/langs/tr/tutorials/async_suspense_list/solved.json @@ -0,0 +1,16 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { Suspense } from \"solid-js\";\n\nimport fetchProfileData from \"./mock-api\";\nimport ProfilePage from \"./profile\";\n\nconst App = () => {\n const { user, posts, trivia } = fetchProfileData();\n return (\n Loading...}>\n \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + }, + { + "name": "profile", + "content": "import { For, Suspense, SuspenseList } from \"solid-js\";\n\nconst ProfileDetails = (props) =>

    {props.user?.name}

    ;\n\nconst ProfileTimeline = (props) => (\n
      \n {(post) =>
    • {post.text}
    • }
      \n
    \n);\n\nconst ProfileTrivia = (props) => (\n <>\n

    Fun Facts

    \n
      \n {(fact) =>
    • {fact.text}
    • }
      \n
    \n \n);\n\nconst ProfilePage = (props) => (\n \n \n Loading posts...}>\n \n \n Loading fun facts...}>\n \n \n \n);\n\nexport default ProfilePage;" + }, + { + "name": "mock-api", + "content": "import { createResource } from \"solid-js\";\n\nexport default function fetchProfileData() {\n const [user] = createResource(fetchUser);\n const [posts] = createResource(fetchPosts);\n const [trivia] = createResource(fetchTrivia);\n return { user, posts, trivia };\n}\n\nfunction fetchUser() {\n console.log(\"fetch user...\");\n return new Promise((resolve) => {\n setTimeout(() => {\n console.log(\"fetched user\");\n resolve({\n name: \"Ringo Starr\"\n });\n }, 500);\n });\n}\n\nlet ringoPosts = [\n {\n id: 0,\n text: \"I get by with a little help from my friends\"\n },\n {\n id: 1,\n text: \"I'd like to be under the sea in an octupus's garden\"\n },\n {\n id: 2,\n text: \"You got that sand all over your feet\"\n }\n];\n\nfunction fetchPosts() {\n let ringoPostsAtTheTime = ringoPosts;\n console.log(\"fetch posts...\");\n return new Promise((resolve) => {\n setTimeout(() => {\n console.log(\"fetched posts\");\n resolve(ringoPostsAtTheTime);\n }, 3000 * Math.random());\n });\n}\n\nfunction fetchTrivia() {\n console.log(\"fetch trivia...\");\n return new Promise((resolve) => {\n setTimeout(() => {\n console.log(\"fetched trivia\");\n resolve([\n {\n id: 1,\n text:\n 'The nickname \"Ringo\" came from his habit of wearing numerous rings.'\n },\n {\n id: 2,\n text: \"Plays the drums left-handed with a right-handed drum set.\"\n },\n {\n id: 3,\n text: \"Nominated for one Daytime Emmy Award, but did not win\"\n }\n ]);\n }, 3000 * Math.random());\n });\n}\n" + } + ] +} diff --git a/langs/tr/tutorials/async_transitions/lesson.json b/langs/tr/tutorials/async_transitions/lesson.json new file mode 100644 index 00000000..b39a168a --- /dev/null +++ b/langs/tr/tutorials/async_transitions/lesson.json @@ -0,0 +1,17 @@ +{ + "files": [ + { + "name": "main", + "content": "import { createSignal, Suspense, Switch, Match, useTransition } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport Child from \"./child\";\n\nimport \"./styles.css\";\n\nconst App = () => {\n const [tab, setTab] = createSignal(0);\n const updateTab = (index) => () => setTab(index);\n\n return (\n <>\n
      \n
    • \n Uno\n
    • \n
    • \n Dos\n
    • \n
    • \n Tres\n
    • \n
    \n
    \n Loading...
    }>\n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + }, + { + "name": "child", + "content": "import { createResource } from \"solid-js\";\n\nconst CONTENT = {\n Uno: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`,\n Dos: `Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?`,\n Tres: `On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains.`\n};\n\nfunction createDelay() {\n return new Promise((resolve) => {\n const delay = Math.random() * 420 + 160;\n setTimeout(() => resolve(delay), delay);\n });\n}\n\nconst Child = (props) => {\n const [time] = createResource(createDelay);\n\n return (\n
    \n This content is for page \"{props.page}\" after {time()?.toFixed()}ms.\n

    {CONTENT[props.page]}

    \n
    \n );\n};\n\nexport default Child;\n" + }, + { + "name": "styles", + "type": "css", + "content": "body{\n background-color:#eee;\n}\n\n#app{\n border-radius:3px;\n border: 1px solid #e5e5e5;\n margin:15px;\n background-color:white;\n}\n\n.tab{\n padding:25px;\n font-family:sans-serif;\n color:#444;\n min-height: 400px;\n}\n\n.pending {\n transition: color .3s;\n transition-delay: .1s;\n transition-timing-function: ease-in;\n color: #aaa;\n}\n\nul.inline{\n list-style:none;\n padding: 0;\n margin-bottom:0;\n -webkit-margin-before: 0;\n -webkit-margin-after: 0;\n -webkit-margin-start: 0px;\n -webkit-margin-end: 0px;\n -webkit-padding-start: 0px;\n}\n\nul.inline li {\n display:inline-block;\n margin-left:0;\n padding:10px;\n border-bottom:2px solid #eee;\n transition: all .5s;\n font-family:sans-serif;\n font-weight: 300;\n cursor:pointer;\n color: #aaa;\n}\n\nul.inline li.selected{\n border-bottom:2px solid #337ab7;\n color:#444;\n}\n\n.loader{\n color:#aaa;\n font-size: 16px;\n font-weight: 600;\n width: 80px;\n}" + } + ] +} diff --git a/langs/tr/tutorials/async_transitions/lesson.md b/langs/tr/tutorials/async_transitions/lesson.md new file mode 100644 index 00000000..b8cd7c3f --- /dev/null +++ b/langs/tr/tutorials/async_transitions/lesson.md @@ -0,0 +1,22 @@ +`Suspense`, veriler yüklenirken fallback içeriği görmemizi sağlar. Bu durum ilk yükleme için harika olsa da devamındaki gezinmeler için iskelet durumuna geri dönmek genellikle daha kötü bir kullanıcı deneyimi yaşatır. + +Bu durumlar için `useTransition` kullanabiliriz ve fallback durumuna geri dönmeyi engelleyebiliriz. `useTransition` bir wrapper ve bir pending indicator sağlar. Wrapper, bütün downstream güncellemeleri bütün asenkron event'ler tamamlanana kadar bekleyen bir transaction'a koyar. + +Bunun anlamı, `useTransition`, kontrol akışı suspend edildiğinde, bir sonraki işlem ekran dışında işlenirken, mevcut durumu görüntülemeye devam eder. Mevcut sınırların içindeki Resource okumaları da transition'a eklenir. Ancak, yeni iç içe geçmiş `Suspense` bileşenleri, görünüme gelmeden önce yüklemeyi tamamlamışlarsa "fallback" göstereceklerdir. + +Örnekte gezinirken, içeriğin loading placeholder'ına geri döndüğüne dikkat edin. `App` bileşenimiz için bir transition ekleyelim. İlk olarak `updateTab` fonksiyonunu değiştirelim: + +```js +const [pending, start] = useTransition(); +const updateTab = (index) => () => start(() => setTab(index)); +``` + +`useTransition` bir bekleyen sinyal göstergesi (pending signal indicator) ve güncellememizin etrafını saracağımız geçişi başlatmak üzere bir metot döndürür. + +Bu bekleyen sinyali kullanıcı arayüzünde bir bilgilendirme oluşturacak şekilde kullanmalıyız. `tab` container `div`'ine bir pending sınıfı ekleyebiliriz: + +```js +
    +``` + +Bu şekilde sekme geçişlerimiz çok daha akıcı olacaktır. diff --git a/langs/tr/tutorials/async_transitions/solved.json b/langs/tr/tutorials/async_transitions/solved.json new file mode 100644 index 00000000..04b7b6bb --- /dev/null +++ b/langs/tr/tutorials/async_transitions/solved.json @@ -0,0 +1,17 @@ +{ + "files": [ + { + "name": "main", + "content": "import { createSignal, Suspense, Switch, Match, useTransition } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport Child from \"./child\";\n\nimport \"./styles.css\";\n\nconst App = () => {\n const [tab, setTab] = createSignal(0);\n const [pending, start] = useTransition();\n const updateTab = (index) => () => start(() => setTab(index));\n\n return (\n <>\n
      \n
    • \n Uno\n
    • \n
    • \n Dos\n
    • \n
    • \n Tres\n
    • \n
    \n
    \n Loading...
    }>\n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + }, + { + "name": "child", + "content": "import { createResource } from \"solid-js\";\n\nconst CONTENT = {\n Uno: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`,\n Dos: `Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?`,\n Tres: `On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains.`\n};\n\nfunction createDelay() {\n return new Promise((resolve) => {\n const delay = Math.random() * 420 + 160;\n setTimeout(() => resolve(delay), delay);\n });\n}\n\nconst Child = (props) => {\n const [time] = createResource(createDelay);\n\n return (\n
    \n This content is for page \"{props.page}\" after {time()?.toFixed()}ms.\n

    {CONTENT[props.page]}

    \n
    \n );\n};\n\nexport default Child;\n" + }, + { + "name": "styles", + "type": "css", + "content": "body{\n background-color:#eee;\n}\n\n#app{\n border-radius:3px;\n border: 1px solid #e5e5e5;\n margin:15px;\n background-color:white;\n}\n\n.tab{\n padding:25px;\n font-family:sans-serif;\n color:#444;\n min-height: 400px;\n}\n\n.pending {\n transition: color .3s;\n transition-delay: .1s;\n transition-timing-function: ease-in;\n color: #aaa;\n}\n\nul.inline{\n list-style:none;\n padding: 0;\n margin-bottom:0;\n -webkit-margin-before: 0;\n -webkit-margin-after: 0;\n -webkit-margin-start: 0px;\n -webkit-margin-end: 0px;\n -webkit-padding-start: 0px;\n}\n\nul.inline li {\n display:inline-block;\n margin-left:0;\n padding:10px;\n border-bottom:2px solid #eee;\n transition: all .5s;\n font-family:sans-serif;\n font-weight: 300;\n cursor:pointer;\n color: #aaa;\n}\n\nul.inline li.selected{\n border-bottom:2px solid #337ab7;\n color:#444;\n}\n\n.loader{\n color:#aaa;\n font-size: 16px;\n font-weight: 600;\n width: 80px;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_classlist/lesson.json b/langs/tr/tutorials/bindings_classlist/lesson.json new file mode 100644 index 00000000..8114b5fe --- /dev/null +++ b/langs/tr/tutorials/bindings_classlist/lesson.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport \"./style.css\";\n\nfunction App() {\n const [current, setCurrent] = createSignal(\"foo\");\n\n return <>\n setCurrent('foo')}\n >foo\n setCurrent('bar')}\n >bar\n setCurrent('baz')}\n >baz\n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "style", + "type": "css", + "content": "button {\n display: block;\n}\n\n.selected {\n background-color: #ff3e00;\n color: white;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_classlist/lesson.md b/langs/tr/tutorials/bindings_classlist/lesson.md new file mode 100644 index 00000000..c6c1647f --- /dev/null +++ b/langs/tr/tutorials/bindings_classlist/lesson.md @@ -0,0 +1,27 @@ +Solid bir öğe üzerinde `className` property'sini ayarlamak için `class` kelimesini kullanır. Ancak class'lara koşul eklemek istediğiniz durumlar olabilir. Bu nedenle Solid, anahtarların class isimleri ve değerin boolean bir ifade olduğu bir obje alan yerleşik bir `classList` JSX attribute'una sahiptir. Boolean karşılığına göre sınıflar uygulanır veya kaldırılır. + +Örneğimizde aşağıdaki kodu: + +```jsx + +``` + +classList kullanacak şekilde değiştirebiliriz: + +```jsx + +``` + +CSS modules'tan aldığınız sınıfları dinamik olarak da uygulayabileceğinizi unutmayın: + +```jsx +import { active } from "./style.module.css" + +
    +``` diff --git a/langs/tr/tutorials/bindings_classlist/solved.json b/langs/tr/tutorials/bindings_classlist/solved.json new file mode 100644 index 00000000..666cf63c --- /dev/null +++ b/langs/tr/tutorials/bindings_classlist/solved.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport \"./style.css\";\n\nfunction App() {\n const [current, setCurrent] = createSignal(\"foo\");\n\n return <>\n setCurrent('foo')}\n >foo\n setCurrent('bar')}\n >bar\n setCurrent('baz')}\n >baz\n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "style", + "type": "css", + "content": "button {\n display: block;\n}\n\n.selected {\n background-color: #ff3e00;\n color: white;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_directives/lesson.json b/langs/tr/tutorials/bindings_directives/lesson.json new file mode 100644 index 00000000..26f8a117 --- /dev/null +++ b/langs/tr/tutorials/bindings_directives/lesson.json @@ -0,0 +1,17 @@ +{ + "files": [ + { + "name": "main", + "content": "// @ts-nocheck\nimport { render } from \"solid-js/web\";\nimport { createSignal, Show } from \"solid-js\";\nimport clickOutside from \"./click-outside\";\nimport \"./style.css\";\n\nfunction App() {\n const [show, setShow] = createSignal(false);\n\n return (\n setShow(true)}>Open Modal}\n >\n
    \n Some Modal\n
    \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "click-outside", + "content": "import { onCleanup } from \"solid-js\";\n\nexport default function clickOutside(el, accessor) {\n // implement here\n}\n" + }, + { + "name": "style", + "type": "css", + "content": ".modal {\n padding: 16px;\n border: 1px solid #444;\n box-shadow: 4px 4px #88888866;\n}" + } + ] +} \ No newline at end of file diff --git a/langs/tr/tutorials/bindings_directives/lesson.md b/langs/tr/tutorials/bindings_directives/lesson.md new file mode 100644 index 00000000..7c675644 --- /dev/null +++ b/langs/tr/tutorials/bindings_directives/lesson.md @@ -0,0 +1,26 @@ +Solid özel direktifleri `use:` namespace'i aracılığı ile destekler. Bu aslında sadece `ref` üzerinde bir syntactic sugar'dır ancak tipik binding'lere benzemesi ve aynı eleman üzerinde çakışma olmadan birden fazla binding olabilmesi açısından kullanışlıdır. + +Özel direktif `(element, valueAccessor)` argümanlarını alan bir fonksiyondur, `element`, `use` attribute'una sahip bir DOM elemanına ve `valueAccessor` da bu attribute'a atanmış değerin getter fonksiyonuna eş düşer. Fonksiyon kapsam (scope) içerisinde aktarıldığı sürece `use:` ile kullanılabilir. + +> Önemli: derleyici `use:`'u dönüştürülmesi gerektiği şeklinde algılar, dolayısıyla fonksiyonun kapsam içerisinde olması gerekir. Bu nedenle spread ile kullanılamaz veya bir bileşene uygulanamaz. + +Örneğimizde, bir popup veya modal'ı dışarı tıklandığında kapanacak şekilde bir wrapper üreteceğiz. Öncelikle `clickOutside` direktifini import etmemiz ve elemanın üzerinde kullanmamız gerekiyor: + +```jsx + +``` + +Özel direktifimizi tanımlayacağımız `click-outside.tsx` doyasını açalım. Bu direktif, body'e bağlayacağımız ve zamanı geldiğinde temizleyeceğimiz bir click handler tanımlamakta: + +```jsx +export default function clickOutside(el, accessor) { + const onClick = (e) => !el.contains(e.target) && accessor()?.(); + document.body.addEventListener("click", onClick); + + onCleanup(() => document.body.removeEventListener("click", onClick)); +} +``` + +Artık modal istenildiği şekilde açılıp kapanma özelliklerine sahip. diff --git a/langs/tr/tutorials/bindings_directives/solved.json b/langs/tr/tutorials/bindings_directives/solved.json new file mode 100644 index 00000000..84830904 --- /dev/null +++ b/langs/tr/tutorials/bindings_directives/solved.json @@ -0,0 +1,17 @@ +{ + "files": [ + { + "name": "main", + "content": "// @ts-nocheck\nimport { render } from \"solid-js/web\";\nimport { createSignal, Show } from \"solid-js\";\nimport clickOutside from \"./click-outside\";\nimport \"./style.css\";\n\nfunction App() {\n const [show, setShow] = createSignal(false);\n\n return (\n setShow(true)}>Open Modal}\n >\n
    setShow(false)}>\n Some Modal\n
    \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "click-outside", + "content": "import { onCleanup } from \"solid-js\";\n\nexport default function clickOutside(el, accessor) {\n const onClick = (e) => !el.contains(e.target) && accessor()?.();\n document.body.addEventListener(\"click\", onClick);\n\n onCleanup(() => document.body.removeEventListener(\"click\", onClick));\n}\n" + }, + { + "name": "style", + "type": "css", + "content": ".modal {\n padding: 16px;\n border: 1px solid #444;\n box-shadow: 4px 4px #88888866;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_events/lesson.json b/langs/tr/tutorials/bindings_events/lesson.json new file mode 100644 index 00000000..0c31e073 --- /dev/null +++ b/langs/tr/tutorials/bindings_events/lesson.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport \"./style.css\";\n\nfunction App() {\n const [pos, setPos] = createSignal({x: 0, y: 0});\n\n function handleMouseMove(event) {\n setPos({\n x: event.clientX,\n y: event.clientY\n });\n }\n\n return (\n
    \n The mouse position is {pos().x} x {pos().y}\n
    \n );\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "style", + "type": "css", + "content": "div { width: 100%; height: 100%; }" + } + ] +} diff --git a/langs/tr/tutorials/bindings_events/lesson.md b/langs/tr/tutorials/bindings_events/lesson.md new file mode 100644 index 00000000..f5fdb760 --- /dev/null +++ b/langs/tr/tutorials/bindings_events/lesson.md @@ -0,0 +1,22 @@ +Solid'deki event'ler `on` ön adına sahip niteliklerdir (attribute) ve birkaç yönden özel olarak ele alınırlar. Öncelikle wrapping konusunda normal buluşsallığı (heuristic) takip etmezler; çoğu durumda, bir sinyal ile bir event handler arasındaki farkı saptamak zordur. Bu nedenle, event'ler çağrıldıklarından ve de güncelleme işlemi için reaktivite gerektirmediklerinden yalnızca başlangıçta bağlanırlar. Handler'ın uygulamanın mevcut durumuna göre farklı kod çalıştırması sağlanılabilir. + +Ortak UI event'leri (bubble oluşturan, oluşturulan) otomatik olarak belgede temsil edilir. Bu bağlamda performansı iyileştirmek için Solid, ek closure'lar oluşturmadan handler'ı verilerle (ilk argüman olarak) çağırmak için bir dizi syntax'ı destekler. + +```jsx +const handler = (data, event) => /*...*/ + + +``` + +Örneğimizde, handler'ı `mousemove` event'ine bağlayalım: +```jsx +
    + The mouse position is {pos().x} x {pos().y} +
    +``` + +Tüm `on` bind'ları (bağ) büyük/küçük harf farkına duyarlı değildir, bu da event adlarının küçük harfle yazılması gerektiği anlamına gelir. Örneğin: `onMouseMove`, `mousemove` event adını izler. Büyük/küçük harf kullanımını desteklemek veya event temsilini (event delegation) kullanmamak istediğiniz durumlarda `on:` namespace'ini iki noktadan sonra gelecek event handler ile eşleşecek şekilde kullanabilirsiniz: + +```jsx + +``` diff --git a/langs/tr/tutorials/bindings_events/solved.json b/langs/tr/tutorials/bindings_events/solved.json new file mode 100644 index 00000000..913e7869 --- /dev/null +++ b/langs/tr/tutorials/bindings_events/solved.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport \"./style.css\";\n\nfunction App() {\n const [pos, setPos] = createSignal({x: 0, y: 0});\n\n function handleMouseMove(event) {\n setPos({\n x: event.clientX,\n y: event.clientY\n });\n }\n\n return (\n
    \n The mouse position is {pos().x} x {pos().y}\n
    \n );\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "style", + "type": "css", + "content": "div { width: 100%; height: 100%; }" + } + ] +} diff --git a/langs/tr/tutorials/bindings_forward_refs/lesson.json b/langs/tr/tutorials/bindings_forward_refs/lesson.json new file mode 100644 index 00000000..ab19dd11 --- /dev/null +++ b/langs/tr/tutorials/bindings_forward_refs/lesson.json @@ -0,0 +1,17 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { onMount, onCleanup } from \"solid-js\";\n\nimport Canvas from \"./canvas\";\n\nfunction App() {\n let canvas;\n onMount(() => {\n const ctx = canvas.getContext(\"2d\");\n let frame = requestAnimationFrame(loop);\n\n function loop(t) {\n frame = requestAnimationFrame(loop);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n for (let p = 0; p < imageData.data.length; p += 4) {\n const i = p / 4;\n const x = i % canvas.width;\n const y = (i / canvas.height) >>> 0;\n\n const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000);\n const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1000);\n const b = 128;\n\n imageData.data[p + 0] = r;\n imageData.data[p + 1] = g;\n imageData.data[p + 2] = b;\n imageData.data[p + 3] = 255;\n }\n\n ctx.putImageData(imageData, 0, 0);\n }\n\n onCleanup(() => cancelAnimationFrame(frame));\n });\n\n return ;\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "canvas", + "content": "import \"./style.css\";\n\nexport default function Canvas(props) {\n return ;\n}\n" + }, + { + "name": "style", + "type": "css", + "content": "canvas {\n background-color: #666;\n -webkit-mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_forward_refs/lesson.md b/langs/tr/tutorials/bindings_forward_refs/lesson.md new file mode 100644 index 00000000..9e86ac75 --- /dev/null +++ b/langs/tr/tutorials/bindings_forward_refs/lesson.md @@ -0,0 +1,9 @@ +Birçok durumda, bir bileşenin içinden bir üst bileşene ref göndermek isteyebilirsiniz. Bunu yapmanın yolu yine `ref` attribute'unu kullanmaktır. Dışarıdan bakıldığında, bir bileşen üzerinde `ref` kullanmak, yerel bir öğe üzerinde ref kullanmaya çok benzer. Dolayısıyla atanacak bir değişken veya bir callback fonksiyonu iletebilir. + +Ancak, geliştiricinin bu `ref`'i geri iletilmek üzere, bileşen içerisinde bir elemana bağlaması gerekir. Bunun için `props.ref` kullanımından yararlanırız. Bu her iki `ref` türü de verildiği takdirde, `ref`' in callback formudur, fakat genelde siz bunu JSX elemanlarından birine veya bir bileşene `ref` attribute'u olarak doğrudan atayacağınız için çoğunlukla bu detay sizden gizlenir. + +Logoyu tekrar hareket ettirmek için ref'i `canvas.tsx`'ten iletmemiz gerekmekte: + +```jsx + +``` diff --git a/langs/tr/tutorials/bindings_forward_refs/solved.json b/langs/tr/tutorials/bindings_forward_refs/solved.json new file mode 100644 index 00000000..40c53fe8 --- /dev/null +++ b/langs/tr/tutorials/bindings_forward_refs/solved.json @@ -0,0 +1,17 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { onMount, onCleanup } from \"solid-js\";\n\nimport Canvas from \"./canvas\";\n\nfunction App() {\n let canvas;\n onMount(() => {\n const ctx = canvas.getContext(\"2d\");\n let frame = requestAnimationFrame(loop);\n\n function loop(t) {\n frame = requestAnimationFrame(loop);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n for (let p = 0; p < imageData.data.length; p += 4) {\n const i = p / 4;\n const x = i % canvas.width;\n const y = (i / canvas.height) >>> 0;\n\n const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000);\n const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1000);\n const b = 128;\n\n imageData.data[p + 0] = r;\n imageData.data[p + 1] = g;\n imageData.data[p + 2] = b;\n imageData.data[p + 3] = 255;\n }\n\n ctx.putImageData(imageData, 0, 0);\n }\n\n onCleanup(() => cancelAnimationFrame(frame));\n });\n\n return ;\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "canvas", + "content": "import \"./style.css\";\n\nexport default function Canvas(props) {\n return ;\n}\n" + }, + { + "name": "style", + "type": "css", + "content": "canvas {\n background-color: #666;\n -webkit-mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n}" + } + ] +} \ No newline at end of file diff --git a/langs/tr/tutorials/bindings_refs/lesson.json b/langs/tr/tutorials/bindings_refs/lesson.json new file mode 100644 index 00000000..efb164bd --- /dev/null +++ b/langs/tr/tutorials/bindings_refs/lesson.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { onMount, onCleanup } from \"solid-js\";\n\nimport \"./style.css\";\n\nfunction App() {\n let canvas;\n onMount(() => {\n const ctx = canvas.getContext(\"2d\");\n let frame = requestAnimationFrame(loop);\n\n function loop(t) {\n frame = requestAnimationFrame(loop);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n for (let p = 0; p < imageData.data.length; p += 4) {\n const i = p / 4;\n const x = i % canvas.width;\n const y = (i / canvas.height) >>> 0;\n\n const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000);\n const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1000);\n const b = 128;\n\n imageData.data[p + 0] = r;\n imageData.data[p + 1] = g;\n imageData.data[p + 2] = b;\n imageData.data[p + 3] = 255;\n }\n\n ctx.putImageData(imageData, 0, 0);\n }\n\n onCleanup(() => cancelAnimationFrame(frame));\n });\n\n return ;\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "style", + "type": "css", + "content": "canvas {\n background-color: #666;\n -webkit-mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_refs/lesson.md b/langs/tr/tutorials/bindings_refs/lesson.md new file mode 100644 index 00000000..0c932b67 --- /dev/null +++ b/langs/tr/tutorials/bindings_refs/lesson.md @@ -0,0 +1,27 @@ +JSX gerçek DOM elemanları oluşturduğu için Solid'de atama yoluyla her zaman bir DOM elemanına referans alabilirsiniz. Örneğin: + +```jsx +const myDiv =
    My Element
    ; +``` + +Ancak Solid'in eleman oluşturma optimizasyonu açısından, elemanları ayırmamanın ve tek bir bitişik JSX şablonu şeklinde kullanmanın yararı vardır. + +Bu durumda `ref` attribute'u ile Solid'deki bir elemanı referans alabilirsiniz. Ref'ler temel olarak yukarıdaki örnekte olduğu gibi birer atamadır, oluşturulma aşamasında yani belge DOM'a eklenmeden önce atanırlar. Bir değişken tanımlayın, `ref` attribute'una atayın ve değişken atanacaktır: + +```jsx +let myDiv; + +
    My Element
    +``` + +Örneğimizde canvas elemanına referans alalım ve animasyon ekleyelim: + +```jsx + +``` + +Ref'ler ayrıca bir callback fonksiyonu biçiminde de kullanılabilir. Böylece, mantığı encapsulate etmek için, özellikle de elemanlar eklenene kadar beklemeniz gerekmediğinde, kullanışlı olabilirler. Örneğin: + +```jsx +
    /* do something with el... */}>My Element
    +``` diff --git a/langs/tr/tutorials/bindings_refs/solved.json b/langs/tr/tutorials/bindings_refs/solved.json new file mode 100644 index 00000000..bb56ea03 --- /dev/null +++ b/langs/tr/tutorials/bindings_refs/solved.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { onMount, onCleanup } from \"solid-js\";\n\nimport \"./style.css\";\n\nfunction App() {\n let canvas;\n onMount(() => {\n const ctx = canvas.getContext(\"2d\");\n let frame = requestAnimationFrame(loop);\n\n function loop(t) {\n frame = requestAnimationFrame(loop);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n for (let p = 0; p < imageData.data.length; p += 4) {\n const i = p / 4;\n const x = i % canvas.width;\n const y = (i / canvas.height) >>> 0;\n\n const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000);\n const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1000);\n const b = 128;\n\n imageData.data[p + 0] = r;\n imageData.data[p + 1] = g;\n imageData.data[p + 2] = b;\n imageData.data[p + 3] = 255;\n }\n\n ctx.putImageData(imageData, 0, 0);\n }\n\n onCleanup(() => cancelAnimationFrame(frame));\n });\n\n return ;\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "style", + "type": "css", + "content": "canvas {\n background-color: #666;\n -webkit-mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n mask: url(https://www.solidjs.com/img/logo/dark-without-wordmark/logo.svg) 50% 50% no-repeat;\n}" + } + ] +} diff --git a/langs/tr/tutorials/bindings_spreads/lesson.json b/langs/tr/tutorials/bindings_spreads/lesson.json new file mode 100644 index 00000000..c89e7f1a --- /dev/null +++ b/langs/tr/tutorials/bindings_spreads/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport Info from \"./info\";\n\nconst pkg = {\n name: \"solid-js\",\n version: 1,\n speed: \"⚡️\",\n website: \"https://solidjs.com\",\n};\n\nfunction App() {\n return (\n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "info", + "content": "export default function Info(props) {\n return (\n

    \n The {props.name} package is {props.speed} fast. Download\n version {props.version} from{\" \"}\n npm and{\" \"}\n learn more here\n

    \n );\n}\n" + } + ] +} diff --git a/langs/tr/tutorials/bindings_spreads/lesson.md b/langs/tr/tutorials/bindings_spreads/lesson.md new file mode 100644 index 00000000..8b90b1a0 --- /dev/null +++ b/langs/tr/tutorials/bindings_spreads/lesson.md @@ -0,0 +1,9 @@ +Bazen bileşen veya elemanların kabul ettiği attribute sayıları değişebilir, bu durumda da attribute'ları teker teker aktarmaktansa obje halinde aktarmak daha mantıklı olabilir. Bu durum özellikle tasarım sistemleri oluştururken yaygınca kullanılan, bir DOM elemanını bileşen içerisine sararken geçerlidir. + +Bunun için spread operatör'ü kullanırız `...`. + +Bu sayede objedeki bütün property'leri aktarabiliriz: + +```jsx + +``` diff --git a/langs/tr/tutorials/bindings_spreads/solved.json b/langs/tr/tutorials/bindings_spreads/solved.json new file mode 100644 index 00000000..fd12259f --- /dev/null +++ b/langs/tr/tutorials/bindings_spreads/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport Info from \"./info\";\n\nconst pkg = {\n name: \"solid-js\",\n version: 1,\n speed: \"⚡️\",\n website: \"https://solidjs.com\",\n};\n\nfunction App() {\n return ;\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "info", + "content": "export default function Info(props) {\n return (\n

    \n The {props.name} package is {props.speed} fast. Download\n version {props.version} from{\" \"}\n npm and{\" \"}\n learn more here\n

    \n );\n}\n" + } + ] +} diff --git a/langs/tr/tutorials/bindings_style/lesson.json b/langs/tr/tutorials/bindings_style/lesson.json new file mode 100644 index 00000000..11f8610e --- /dev/null +++ b/langs/tr/tutorials/bindings_style/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nfunction App() {\n const [num, setNum] = createSignal(0);\n setInterval(() => setNum((num() + 1) % 255), 30)\n\n return
    Some Text
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/bindings_style/lesson.md b/langs/tr/tutorials/bindings_style/lesson.md new file mode 100644 index 00000000..08e954b5 --- /dev/null +++ b/langs/tr/tutorials/bindings_style/lesson.md @@ -0,0 +1,20 @@ +Solid'deki style attribute'u style string'leri veya objeleri kabul eder. +Ancak nesne formu `Element.prototype.style`'dan farklıdır, aslında `style.setProperty`'yi çağıran bir sarıcıdır (wrapper). Sonuç olarak anahtarlar (key) dash-case yazılır, örneğin "backgroundColor" yerine "background-color" kullanılmalıdır. Ayrıca herhangi bir birim açıkça belirtilmelidir (`width: 500` geçersiz olacaktır, doğru kullanım ise: `width: 500px` şeklindedir) + + +Bu aynı zamanda CSS değişkenleri atayabileceğimiz anlamına da gelir: + +```js +
    +``` + +Div'imizi bir kaç satır içi (inline) style ile hareketli hale getirelim: +```jsx +
    + Some Text +
    +``` \ No newline at end of file diff --git a/langs/tr/tutorials/bindings_style/solved.json b/langs/tr/tutorials/bindings_style/solved.json new file mode 100644 index 00000000..5915cfbf --- /dev/null +++ b/langs/tr/tutorials/bindings_style/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nfunction App() {\n const [num, setNum] = createSignal(0);\n setInterval(() => setNum((num() + 1) % 255), 30)\n\n return (\n
    \n Some Text\n
    \n );\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/directory.json b/langs/tr/tutorials/directory.json new file mode 100644 index 00000000..ede4aeaf --- /dev/null +++ b/langs/tr/tutorials/directory.json @@ -0,0 +1,162 @@ +[ + { + "lessonName": "Introduction/Basics", + "internalName": "introduction_basics" + }, + { + "lessonName": "Introduction/JSX", + "internalName": "introduction_jsx" + }, + { + "lessonName": "Introduction/Components", + "internalName": "introduction_components" + }, + { + "lessonName": "Introduction/Signals", + "internalName": "introduction_signals" + }, + { + "lessonName": "Introduction/Effects", + "internalName": "introduction_effects" + }, + { + "lessonName": "Introduction/Derived Signals", + "internalName": "introduction_derived" + }, + { + "lessonName": "Introduction/Memos", + "internalName": "introduction_memos" + }, + { + "lessonName": "Control Flow/Show", + "internalName": "flow_show" + }, + { + "lessonName": "Control Flow/For", + "internalName": "flow_for" + }, + { + "lessonName": "Control Flow/Index", + "internalName": "flow_index" + }, + { + "lessonName": "Control Flow/Switch", + "internalName": "flow_switch" + }, + { + "lessonName": "Control Flow/Dynamic", + "internalName": "flow_dynamic" + }, + { + "lessonName": "Control Flow/Portal", + "internalName": "flow_portal" + }, + { + "lessonName": "Control Flow/Error Boundary", + "internalName": "flow_error_boundary" + }, + { + "lessonName": "Lifecycles/onMount", + "internalName": "lifecycles_onmount" + }, + { + "lessonName": "Lifecycles/onCleanup", + "internalName": "lifecycles_oncleanup" + }, + { + "lessonName": "Bindings/Events", + "internalName": "bindings_events" + }, + { + "lessonName": "Bindings/Style", + "internalName": "bindings_style" + }, + { + "lessonName": "Bindings/ClassList", + "internalName": "bindings_classlist" + }, + { + "lessonName": "Bindings/Refs", + "internalName": "bindings_refs" + }, + { + "lessonName": "Bindings/Forwarding Refs", + "internalName": "bindings_forward_refs" + }, + { + "lessonName": "Bindings/Spreads", + "internalName": "bindings_spreads" + }, + { + "lessonName": "Bindings/Directives", + "internalName": "bindings_directives" + }, + { + "lessonName": "Props/Default Props", + "internalName": "props_defaults" + }, + { + "lessonName": "Props/Splitting Props", + "internalName": "props_split" + }, + { + "lessonName": "Props/Children", + "internalName": "props_children" + }, + { + "lessonName": "Stores/Nested Reactivity", + "internalName": "stores_nested_reactivity" + }, + { + "lessonName": "Stores/Create Store", + "internalName": "stores_createstore" + }, + { + "lessonName": "Stores/Mutation", + "internalName": "stores_mutation" + }, + { + "lessonName": "Stores/Context", + "internalName": "stores_context" + }, + { + "lessonName": "Stores/Immutable Stores", + "internalName": "stores_immutable" + }, + { + "lessonName": "Stores/Without Context", + "internalName": "stores_nocontext" + }, + { + "lessonName": "Reactivity/Batching Updates", + "internalName": "reactivity_batch" + }, + { + "lessonName": "Reactivity/Untrack", + "internalName": "reactivity_untrack" + }, + { + "lessonName": "Reactivity/On", + "internalName": "reactivity_on" + }, + { + "lessonName": "Async/Lazy Components", + "internalName": "async_lazy" + }, + { + "lessonName": "Async/Resources", + "internalName": "async_resources" + }, + { + "lessonName": "Async/Suspense", + "internalName": "async_suspense" + }, + { + "lessonName": "Async/Suspense List", + "internalName": "async_suspense_list" + }, + { + "lessonName": "Async/Transitions", + "internalName": "async_transitions" + } +] diff --git a/langs/tr/tutorials/flow_dynamic/lesson.json b/langs/tr/tutorials/flow_dynamic/lesson.json new file mode 100644 index 00000000..4d9a171d --- /dev/null +++ b/langs/tr/tutorials/flow_dynamic/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render, Dynamic } from \"solid-js/web\";\nimport { createSignal, Switch, Match, For } from \"solid-js\";\n\nconst RedThing = () => Red Thing;\nconst GreenThing = () => Green Thing;\nconst BlueThing = () => Blue Thing;\n\nconst options = {\n red: RedThing,\n green: GreenThing,\n blue: BlueThing\n}\n\nfunction App() {\n const [selected, setSelected] = createSignal(\"red\");\n\n return (\n <>\n \n }>\n \n \n \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_dynamic/lesson.md b/langs/tr/tutorials/flow_dynamic/lesson.md new file mode 100644 index 00000000..5cbf555a --- /dev/null +++ b/langs/tr/tutorials/flow_dynamic/lesson.md @@ -0,0 +1,18 @@ +`` etiketi verilerden render yapacağınız durumlarda kullanışlıdır. İçerisine native elemanlar için string veya bileşen fonksiyonu iletilebilir ve sonuçta sağlanan diğer prop'lar ile beraber ilettiğiniz eleman render edilir. + +`` bileşeni genellikle ard arda yazılmış `` veya `` ile karşılaştırıldığında daha kısa ve etkili bir kullanım sağlar. + +Örneğimizdeki `` ifadesini: + +```jsx +}> + + + +``` + +aşağıdaki kullanım ile değiştirebiliriz: + +```jsx + +``` diff --git a/langs/tr/tutorials/flow_dynamic/solved.json b/langs/tr/tutorials/flow_dynamic/solved.json new file mode 100644 index 00000000..b8a845b8 --- /dev/null +++ b/langs/tr/tutorials/flow_dynamic/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render, Dynamic } from \"solid-js/web\";\nimport { createSignal, For } from \"solid-js\";\n\nconst RedThing = () => Red Thing;\nconst GreenThing = () => Green Thing;\nconst BlueThing = () => Blue Thing;\n\nconst options = {\n red: RedThing,\n green: GreenThing,\n blue: BlueThing\n}\n\nfunction App() {\n const [selected, setSelected] = createSignal(\"red\");\n\n return (\n <>\n \n \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_error_boundary/lesson.json b/langs/tr/tutorials/flow_error_boundary/lesson.json new file mode 100644 index 00000000..be53fdac --- /dev/null +++ b/langs/tr/tutorials/flow_error_boundary/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { ErrorBoundary } from \"solid-js\";\n\nconst Broken = (props) => {\n throw new Error(\"Oh No\");\n return <>Never Getting Here\n}\n\nfunction App() {\n return (\n <>\n
    Before
    \n \n
    After
    \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_error_boundary/lesson.md b/langs/tr/tutorials/flow_error_boundary/lesson.md new file mode 100644 index 00000000..84ee9a1e --- /dev/null +++ b/langs/tr/tutorials/flow_error_boundary/lesson.md @@ -0,0 +1,9 @@ +UI kaynaklı bir JavaScript hatasının tüm uygulamayı bozmaması gerekir. Error boundaries (Hata sınırları), child bileşen ağacındaki bir JavaScript hatasını yakalayan, loglayan ve sonrasında hata alınan bileşen ağacı yerine fallback UI'ı görüntüleyen bileşenlerdir. + +Örneğimizde hata sonucu çöken bir bileşen var, bileşeni hatayı gösterecek şekilde Error Boundary ile saralım. + +```jsx + err}> + + +``` diff --git a/langs/tr/tutorials/flow_error_boundary/solved.json b/langs/tr/tutorials/flow_error_boundary/solved.json new file mode 100644 index 00000000..25ed4b57 --- /dev/null +++ b/langs/tr/tutorials/flow_error_boundary/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { ErrorBoundary } from \"solid-js\";\n\nconst Broken = (props) => {\n throw new Error(\"Oh No\");\n return <>Never Getting Here\n}\n\nfunction App() {\n return (\n <>\n
    Before
    \n err}>\n \n \n
    After
    \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_for/lesson.json b/langs/tr/tutorials/flow_for/lesson.json new file mode 100644 index 00000000..4b1b4150 --- /dev/null +++ b/langs/tr/tutorials/flow_for/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, For } from 'solid-js';\n\nfunction App() {\n const [cats, setCats] = createSignal([\n { id: 'J---aiyznGQ', name: 'Keyboard Cat' },\n { id: 'z_AbfPXTKms', name: 'Maru' },\n { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }\n ]);\n \n return (\n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_for/lesson.md b/langs/tr/tutorials/flow_for/lesson.md new file mode 100644 index 00000000..2759d2be --- /dev/null +++ b/langs/tr/tutorials/flow_for/lesson.md @@ -0,0 +1,19 @@ +`` bileşeni objelerden oluşan bir array üzerinde döngü oluşturmanın en iyi yoludur. Array değiştiği takdirde `` ögelerin yeniden oluşturulması yerine DOM üzerinde güncellenmesi veya taşınmasını sağlar. Gelin örneğe bir bakalım. + +```jsx +{(cat, i) => +
  • + + {i() + 1}: {cat.name} + +
  • +}
    +``` + +`` bileşeni için sadece bir prop vardır: `each`. Döngü oluşturacağınız array `each`'a aktarılır. + +Sonrasında, `` ve `` arasına doğrudan node'ları yazmak yerine _callback_ fonksiyonu aktarılır. Bu fonksiyon JavaScript'in [`map` callback](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#parameters) fonksiyonuna benzemektedir. Array'deki her eleman için, eleman ilk argüman olarak ve index ikinci argüman olarak geri çağrılır. (Bu örnekte `cat` ve `i`.) Daha sonra, işlenecek bir node döndürmesi gereken callback'te bu değerleri kullanabilirsiniz. + +Dikkat edilmesi gereken bir diğer konu da index'in sabit bir sayı değil bir _sinyal_ oluşudur. Bunun nedeni `` un referansla anahtarlanmış (keyed by reference) olmasıdır: işlenilen her bir node array'deki bir elemana bağlıdır. Başka bir deyişle, bir ögenin array'deki yeri değiştirildiğinde yok edilip yeniden oluşturulmak yerine, ilgili node da hareket edecek ve index'i değiştirecektir. + +`each` prop'u bir array beklemektedir ancak [`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from), [`Object.keys`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys), veya [`spread syntax`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) gibi yardımcılarla diğer yinelenebilir nesneleri array'lere dönüştürebilirsiniz. \ No newline at end of file diff --git a/langs/tr/tutorials/flow_for/solved.json b/langs/tr/tutorials/flow_for/solved.json new file mode 100644 index 00000000..b2b2d8ba --- /dev/null +++ b/langs/tr/tutorials/flow_for/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, For } from 'solid-js';\n\nfunction App() {\n const [cats, setCats] = createSignal([\n { id: 'J---aiyznGQ', name: 'Keyboard Cat' },\n { id: 'z_AbfPXTKms', name: 'Maru' },\n { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }\n ]);\n \n return (\n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_index/lesson.json b/langs/tr/tutorials/flow_index/lesson.json new file mode 100644 index 00000000..dfffada6 --- /dev/null +++ b/langs/tr/tutorials/flow_index/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, Index } from 'solid-js';\n\nfunction App() {\n const [cats, setCats] = createSignal([\n { id: 'J---aiyznGQ', name: 'Keyboard Cat' },\n { id: 'z_AbfPXTKms', name: 'Maru' },\n { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }\n ]);\n \n return (\n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_index/lesson.md b/langs/tr/tutorials/flow_index/lesson.md new file mode 100644 index 00000000..f2594b00 --- /dev/null +++ b/langs/tr/tutorials/flow_index/lesson.md @@ -0,0 +1,21 @@ +Artık Solid'de `` ile bir listeyi nasıl oluşturacağınızı biliyorsunuz, ancak Solid belirli durumlarda daha az re-render üretecek `` bileşeni de sağlamaktadır. + +Array güncellendiğinde `` bileşeni elemanları array'in son durumu ile karşılaştırmak için referans eşitliğini kullanır fakat bu her zaman arzulanan bir durum olmayabilir. + +JavaScript'te primitifler (string veya number gibi) her zaman değerlerine göre karşılaştırılır. `` bileşenini primitif değerlerle veya array'lerden oluşan array'ler ile kullanmak gereksiz render'lara sebep olabilir. Örneğin, bir string listesini her biri düzenlenebilen `` alanlarına eşlemek için `` kullansaydık, bu değerdeki her değişiklik ``'un yeniden oluşturulmasına neden olurdu. + +Bu durumlar için `` bileşeni sağlanmıştır. Genel bir kural olarak, primitif ögelerle çalışırken `` bileşenini kullanın. + +```jsx +{(cat, i) => +
  • + + {i + 1}: {cat().name} + +
  • +}
    +``` + +``, `` ile benzer bir imzaya sahiptir, ancak bu kez öge sinyaldir ve index sabittir. Oluşturulan her node array'deki bir noktaya karşılık gelir ve bu noktadaki veri her değiştiğinde, sinyal güncellenir. + +`` array'deki her bir veri parçasıyla ilgilenir ve bu verilerin konumu değişebilir; `` ise array'deki her bir index'le ilgilenir ve her index'in içeriği değişebilir. diff --git a/langs/tr/tutorials/flow_index/solved.json b/langs/tr/tutorials/flow_index/solved.json new file mode 100644 index 00000000..0fb0f59e --- /dev/null +++ b/langs/tr/tutorials/flow_index/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, Index } from 'solid-js';\n\nfunction App() {\n const [cats, setCats] = createSignal([\n { id: 'J---aiyznGQ', name: 'Keyboard Cat' },\n { id: 'z_AbfPXTKms', name: 'Maru' },\n { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }\n ]);\n \n return (\n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_portal/lesson.json b/langs/tr/tutorials/flow_portal/lesson.json new file mode 100644 index 00000000..024fe7fa --- /dev/null +++ b/langs/tr/tutorials/flow_portal/lesson.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render, Portal } from \"solid-js/web\";\nimport \"./styles.css\";\n\nfunction App() {\n return (\n
    \n

    Just some text inside a div that has a restricted size.

    \n
    \n

    Popup

    \n

    Some text you might need for something or other.

    \n
    \n
    \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "styles", + "type": "css", + "content": ".app-container {\n width: 200px;\n height: 100px;\n overflow: hidden;\n}\n\n.popup {\n position: relative;\n z-index: 2;\n background: #ddd;\n padding: 1rem;\n min-height: 200px;\n min-width: 200px;\n}\n\n.popup::after {\n content: \" \";\n position: absolute;\n bottom: 100%;\n left: 50%;\n margin-left: -5px;\n border-width: 5px;\n border-style: solid;\n border-color: transparent transparent #ddd transparent;\n}" + } + ] +} diff --git a/langs/tr/tutorials/flow_portal/lesson.md b/langs/tr/tutorials/flow_portal/lesson.md new file mode 100644 index 00000000..45390ee0 --- /dev/null +++ b/langs/tr/tutorials/flow_portal/lesson.md @@ -0,0 +1,14 @@ +Bazen ögeleri uygulamanın normal akışının dışına çıkarmak faydalı olabilir. Z-indeksleri de bazen modal'lar gibi floating (kayan) ögelerin render bağlamları ile uyumunda yetersiz kalabilir. + +Solid bu probleme cevap olarak `` bileşenini sunar, işlevi child (alt, içerdiği, sardığı) içeriğini belirlenen konuma eklemektir. Varsayılan olarak sardığı ögeler `document.body` içerisinde bir `
    ` içinde render edilir. + +Örneğimizde, bilgi popup'ının kesildiğini görüyoruz. Bu sorunu, ögeyi bir `` içerisine alarak, dolayısıyla akıştan çıkararak çözebiliriz. + +```jsx + + + +``` diff --git a/langs/tr/tutorials/flow_portal/solved.json b/langs/tr/tutorials/flow_portal/solved.json new file mode 100644 index 00000000..2de9f10b --- /dev/null +++ b/langs/tr/tutorials/flow_portal/solved.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render, Portal } from \"solid-js/web\";\nimport \"./styles.css\";\n\nfunction App() {\n return (\n
    \n

    Just some text inside a div that has a restricted size.

    \n \n
    \n

    Popup

    \n

    Some text you might need for something or other.

    \n
    \n
    \n
    \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "styles", + "type": "css", + "content": ".app-container {\n width: 200px;\n height: 100px;\n overflow: hidden;\n}\n\n.popup {\n position: relative;\n z-index: 2;\n background: #ddd;\n padding: 1rem;\n min-height: 200px;\n min-width: 200px;\n}\n\n.popup::after {\n content: \" \";\n position: absolute;\n bottom: 100%;\n left: 50%;\n margin-left: -5px;\n border-width: 5px;\n border-style: solid;\n border-color: transparent transparent #ddd transparent;\n}" + } + ] +} diff --git a/langs/tr/tutorials/flow_show/lesson.json b/langs/tr/tutorials/flow_show/lesson.json new file mode 100644 index 00000000..53afe6f3 --- /dev/null +++ b/langs/tr/tutorials/flow_show/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, Show } from 'solid-js';\n\nfunction App() {\n const [loggedIn, setLoggedIn] = createSignal(false);\n const toggle = () => setLoggedIn(!loggedIn())\n \n return (\n <>\n \n \n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_show/lesson.md b/langs/tr/tutorials/flow_show/lesson.md new file mode 100644 index 00000000..0347d2a3 --- /dev/null +++ b/langs/tr/tutorials/flow_show/lesson.md @@ -0,0 +1,16 @@ +JSX, templatelardaki mantık akışlarını kontrol etmek için JavaScript kullanmanıza olanak sağlar. Ancak, Virtual DOM olmadan `Array.prototype.map` gibi kullanımlar, her güncellemede tüm DOM node'larını gerek olmadığı halde yeniden oluşturacaktır. Bunun yerine Reactive kütüphanelerde template helper'lar kullanılması yaygındır. Solid içerisinde biz bunları bileşenler içerisine sardık. + +En temel kontrol akışı (control flow) koşuldur. Solid derleyicisi ternary ifadeleri (`a ? b : c`) ve boolean ifadeleri (`a && b`) optimal şekilde işleyecek kadar akıllıdır, ancak okuma kolaylığı bağlamında Solid'in `` bileşeni genellikle daha kullanışlıdır. + +Örnekte, yalnızca mevcut durumu gösteren (kullanıcı girişi yapılıp yapılmadığı) bir buton var. JSX'i aşağıdaki şekilde güncelleyin: +```jsx +Log in} +> + + +``` +`fallback` prop'u `else` işlevi görür ve `when`'e ilişkilendirilen koşul truthy olmadığında gösterilir. + +Artık butona tıklamak beklenildiği gibi iki durum arasında ileri geri geçiş yapmamızı sağlamakta. diff --git a/langs/tr/tutorials/flow_show/solved.json b/langs/tr/tutorials/flow_show/solved.json new file mode 100644 index 00000000..9f8ffe63 --- /dev/null +++ b/langs/tr/tutorials/flow_show/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, Show } from 'solid-js';\n\nfunction App() {\n const [loggedIn, setLoggedIn] = createSignal(false);\n const toggle = () => setLoggedIn(!loggedIn())\n \n return (\n Log in}\n >\n \n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_switch/lesson.json b/langs/tr/tutorials/flow_switch/lesson.json new file mode 100644 index 00000000..7ae3bc59 --- /dev/null +++ b/langs/tr/tutorials/flow_switch/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, Show, Switch, Match } from \"solid-js\";\n\nfunction App() {\n const [x] = createSignal(7);\n\n return (\n 10}\n fallback={\n x()}\n fallback={

    {x()} is between 5 and 10

    }\n >\n

    {x()} is less than 5

    \n \n }\n >\n

    {x()} is greater than 10

    \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/flow_switch/lesson.md b/langs/tr/tutorials/flow_switch/lesson.md new file mode 100644 index 00000000..a8aaa333 --- /dev/null +++ b/langs/tr/tutorials/flow_switch/lesson.md @@ -0,0 +1,16 @@ +Bazen ikiden fazla durumu kapsayan koşullu ifadeler kullanmanız gerekebilir. Bu durum için, kabaca JavaScript'in `switch`/`case` özelliğine karşılık olarak tasarlanan Solid'in `` ve `` bileşenlerini kullanabiliriz. + +Switch, ilk eşleşen koşulu işlemek (render) için sırası ile deneyecek ve eşleşen koşul işlendiğinde duracaktır. Bütün koşullar başarısız olduğu takdirde ise fallback'i işleyecektir. + +Örneğimizde, iç içe geçmiş `` bileşenimizi aşağıdaki kullanım ile değiştirebiliriz: + +```jsx +{x()} is between 5 and 10

    }> + 10}> +

    {x()} is greater than 10

    +
    + x()}> +

    {x()} is less than 5

    +
    +
    +``` diff --git a/langs/tr/tutorials/flow_switch/solved.json b/langs/tr/tutorials/flow_switch/solved.json new file mode 100644 index 00000000..0900e88c --- /dev/null +++ b/langs/tr/tutorials/flow_switch/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, Switch, Match } from \"solid-js\";\n\nfunction App() {\n const [x] = createSignal(7);\n\n return (\n {x()} is between 5 and 10

    }>\n 10} >\n

    {x()} is greater than 10

    \n
    \n x()}>\n

    {x()} is less than 5

    \n
    \n
    \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_basics/lesson.json b/langs/tr/tutorials/introduction_basics/lesson.json new file mode 100644 index 00000000..0d9dc883 --- /dev/null +++ b/langs/tr/tutorials/introduction_basics/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\n\nfunction HelloWorld() {\n return
    Hello World!
    ;\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_basics/lesson.md b/langs/tr/tutorials/introduction_basics/lesson.md new file mode 100644 index 00000000..39783bd4 --- /dev/null +++ b/langs/tr/tutorials/introduction_basics/lesson.md @@ -0,0 +1,29 @@ +# Giriş + +Bu interaktif rehber Solid'in ana özelliklerini anlamanızda size yol gösterecektir. Solid'in nasıl çalıştığı hakkında daha fazla bilgi edinmek için API ve rehberlere da başvurabilirsiniz. + +Ayrıca yeni başlangıç rehberimize de [buradan](https://docs.solidjs.com/tutorials/getting-started-with-solid/) göz atabilirsiniz.(hazırlık aşamasında!) + +# Solid Nedir + +Solid interaktif web uygulamaları üretmeye yönelik bir Javascript framework'üdür. +Solid ile mevcut HTML ve Javascript bilginizi kullanarak uygulamalarınızda yeniden kullanılabilir bileşenler (component) üretebilirsiniz. +Solid, bileşenleri _reaktivite_ özelliklerine sahip bir şekilde geliştirmek için araçlar sunar: bu sayede deklaratif Javascript kodu ile, kullanıcı arayüzü ve kullanıcı arayüzünü oluşturan, kullanan verinin birlikte çalışmasını sağlar. + +# Solid Uygulamasının Anatomisi + +Solid uygulaması bileşen (component) olarak adlandırdığımız fonksiyonlardan oluşur. Sağdaki `HelloWorld` fonksiyonuna baktığımızda doğrudan `dıv` döndüğünü görüyoruz! Bu HTML ve Javascript karışımı JSX olarak adlandırılmaktadır. Solid bu etiketleri daha sonra DOM nodelarına dönüştüren bir derleyici içermektedir. + +JSX, uygulamanızdaki çoğu HTML elementlerini kullanmanıza izin verir, ancak aynı zamanda yeni ögeler üretmenize de olanak tanır. `HelloWorld` fonksiyonumuzu bir kez oluşturduktan sonra uygulamamızın tamamında `` tag'ı ile kullanabiliriz. + +Solid Uygulamasının giriş noktası `render` fonksiyonudur. Bu fonksiyon 2 argüman alır: birincisi uygulamamızın kodunu saran bir fonksiyon, ikincisi ise HTML de mevcut, uygulamanın bağlanacağı elemandır. + +```jsx +render(() => , document.getElementById("app")); +``` + +# Rehberden Yararlanmak + +Eğitimdeki her bir ders bir Solid özelliğine eş düşmektedir ve bunu denemek için sizlere bir senaryo sunmaktadır. Herhangi bir noktada çözümü görmek için Çöz düğmesine tıklayabilir veya baştan başlamak için sıfırla düğmesine tıklayabilirsiniz. Kod düzenleyicisinin kendisinde bir konsol ve kodunuzdan oluşturulan derlenmiş çıktıyı görebileceğiniz bir output sekmesi vardır. Solid'in nasıl kod ürettiğini merak ediyorsanız bakabilirsiniz. + +İyi eğlenceler! \ No newline at end of file diff --git a/langs/tr/tutorials/introduction_basics/solved.json b/langs/tr/tutorials/introduction_basics/solved.json new file mode 100644 index 00000000..31200eb3 --- /dev/null +++ b/langs/tr/tutorials/introduction_basics/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\n\nfunction HelloWorld() {\n return
    Hello Solid World!
    ;\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_components/lesson.json b/langs/tr/tutorials/introduction_components/lesson.json new file mode 100644 index 00000000..3e0d70ed --- /dev/null +++ b/langs/tr/tutorials/introduction_components/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\n\nfunction App() {\n return (\n

    This is a Header

    \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "nested", + "content": "export default () =>

    This is a Paragraph

    " + } + ] +} diff --git a/langs/tr/tutorials/introduction_components/lesson.md b/langs/tr/tutorials/introduction_components/lesson.md new file mode 100644 index 00000000..bdf3213c --- /dev/null +++ b/langs/tr/tutorials/introduction_components/lesson.md @@ -0,0 +1,24 @@ +Uygulamalarınızı oluştururken kodunuzu parçalara bölmek isteyebilirsiniz, bu tekrar kullanılabilirlik ve modülerlik konularında yararlı olacaktır. Solid'te bunu yapmanın ana yolu bileşen (component) oluşturmaktır. + +Bileşenler temelde `HelloWorld()` - şimdiye kadar kullanmakta olduğumuz - gibi birer fonksiyondur. Bileşenleri özel yapan şey, genellikle JSX döndürmeleri ve diğer bileşenlerde JSX tarafından çağırılabilmeleridir. + +Hadi örneğimizde `Nested` bileşenimizi uygulamamıza ekleyelim. Bileşeni başka bir dosyada tanımladık, ancak aynı dosyada birden fazla bileşen de barınabilir. Öncelikle aşağıdaki kodu ekleyelim. + +```js +import Nested from "./nested"; +``` + +Sonra bileşenimizi JSX'e ekleyelim. Daha önce bahsedildiği gibi, döndürmek istediğimiz birden fazla elemanımız var, dolayısıyla bu elemanları Fragment ile sarmalıyız. + +```jsx +function App() { + return ( + <> +

    This is a Header

    + + + ); +} +``` + +Ana bileşen ilk kez oluştuğunda `Nested()` fonksiyonunu çalıştıracaktır ve bir daha asla çağırmayacaktır. Sonrasındaki tüm değişiklikler Solid'in önümüzdeki derslerde göreceğimiz reaktivite sistemi tarafından gerçekleştirilecektir. \ No newline at end of file diff --git a/langs/tr/tutorials/introduction_components/solved.json b/langs/tr/tutorials/introduction_components/solved.json new file mode 100644 index 00000000..3a259599 --- /dev/null +++ b/langs/tr/tutorials/introduction_components/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport Nested from \"./nested\";\n\nfunction App() {\n return (\n <>\n

    This is a Header

    \n \n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "nested", + "content": "export default () =>

    This is a Paragraph

    " + } + ] +} diff --git a/langs/tr/tutorials/introduction_derived/lesson.json b/langs/tr/tutorials/introduction_derived/lesson.json new file mode 100644 index 00000000..266f7a15 --- /dev/null +++ b/langs/tr/tutorials/introduction_derived/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n\n setInterval(() => setCount(count() + 1), 1000);\n\n return
    Count: {count()}
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/introduction_derived/lesson.md b/langs/tr/tutorials/introduction_derived/lesson.md new file mode 100644 index 00000000..7d212ff0 --- /dev/null +++ b/langs/tr/tutorials/introduction_derived/lesson.md @@ -0,0 +1,16 @@ +JSX ile bir sinyale her erişildiğinde, görünümün de bu sinyale bağlı olarak otomatik olarak güncellendiğini gördük. Ancak, bileşen fonksiyonunun kendisi sadece bir kez çalışmaktadır. + +Bir sinyali başka bir fonksiyon ile sararak sinyale bağlı yeni ifadeler oluşturulabilir. Bu sinyale erişen fonksiyonun kendisi de aynı zamanda bir sinyaldir: sardığı sinyal değiştiğinde fonksiyona erişmekte olan okuyucular da güncellenecektir. + +Counter'ı, artık ikişer ikişer saymak üzere, `doubleCount` fonksiyonu ile güncelleyelim: + +```jsx +const doubleCount = () => count() * 2; +``` + +Sonrasında `doubleCount` fonksiyonunu, bir sinyali nasıl çağırıyorsak aynı şekilde JSX üzerinde çağırabiliriz: +```jsx +return
    Count: {doubleCount()}
    ; +``` + +Bu tür fonksiyonlara _derived signal_ (türetilmiş sinyal) diyoruz çünkü reaktiviteleri eriştikleri sinyalden gelmekte. Kendileri bir değer saklamazlar, (bir derived signal oluşturur ve onu hiç çağırmazsanız, kullanılmayan herhangi bir fonksiyon gibi Solid'in çıktısından çıkarılacaktır) ancak kendilerine bağlı olan tüm efektleri güncellerler ve bir görünüme dahil edildiklerinde re-render'ı tetiklerler. \ No newline at end of file diff --git a/langs/tr/tutorials/introduction_derived/solved.json b/langs/tr/tutorials/introduction_derived/solved.json new file mode 100644 index 00000000..71bf7c80 --- /dev/null +++ b/langs/tr/tutorials/introduction_derived/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n const doubleCount = () => count() * 2;\n\n setInterval(() => setCount(count() + 1), 1000);\n\n return
    Count: {doubleCount()}
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/introduction_effects/lesson.json b/langs/tr/tutorials/introduction_effects/lesson.json new file mode 100644 index 00000000..f5176ea0 --- /dev/null +++ b/langs/tr/tutorials/introduction_effects/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, createEffect } from 'solid-js';\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n\n return ;\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_effects/lesson.md b/langs/tr/tutorials/introduction_effects/lesson.md new file mode 100644 index 00000000..b6a11ade --- /dev/null +++ b/langs/tr/tutorials/introduction_effects/lesson.md @@ -0,0 +1,21 @@ +Sinyaller takip edilebilir değerlerdir, ancak bu denklemin sadece yarısıdır. Tamamlanması için bu izlenebilir değerler tarafından güncellenebilen gözlemciler kullanılır. Effect bir gözlemcidir ve işlevi sinyale bağlı bir side-effect çalıştırmaktır. + +Effect oluşturmak için `solid-js`'ten `createEffect`'i import ediyoruz ve içerisinde bir fonksiyon oluşturuyoruz. Effect otomatik olarak fonksiyon çalışırken okunan sinyallere subscribe olur ve bunlardan birisi değiştiğinde fonksiyonu yeniden çalıştırır. + +Hadi `count` her değiştiğine çalışan bir Effect oluşturalım. + +```jsx +createEffect(() => { + console.log("The count is now", count()); +}); +``` + +`count` sinyalimizi güncellemek için bir butona tıklandığında çalışacak bir fonksiyon atayalım. + +```jsx + +``` + +Artık her butona tıklandığında konsol'a yazıyor. Bu örnek görece basit bir örnek, fakat Solid'in nasıl çalıştığını anlamak için, JXT içindeki her ifadenin bağımlı sinyalleri değiştiğinde yeniden çalıştırılan kendine ait bir effect olduğunu hayal etmelisiniz. Solid içerisindeki bütün render işlemleri bu şekilde çalışır, Solid perspektifinde: *bütün render işlemleri reaktif sistemin bir side effect'idir*. + +> Geliştiricinin `createEffect` ile oluşturduğu effectler render işlemi tamamlandıktan sonra çalışır ve çoğunlukla DOM ile etkileşime giren güncellemeleri zamanlamak için kullanılırlar. DOM'u öncesinde değiştirmek istiyorsanız [`createRenderEffect`](https://www.solidjs.com/docs/latest/api#createrendereffect) kullanabilirsiniz. \ No newline at end of file diff --git a/langs/tr/tutorials/introduction_effects/solved.json b/langs/tr/tutorials/introduction_effects/solved.json new file mode 100644 index 00000000..8732c699 --- /dev/null +++ b/langs/tr/tutorials/introduction_effects/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, createEffect } from 'solid-js';\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n createEffect(() => {\n console.log(\"The count is now\", count());\n });\n\n return ;\n}\n\nrender(() => , document.getElementById('app'));\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_jsx/lesson.json b/langs/tr/tutorials/introduction_jsx/lesson.json new file mode 100644 index 00000000..5837d9df --- /dev/null +++ b/langs/tr/tutorials/introduction_jsx/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\n\nfunction HelloWorld() {\n const name = \"Solid\";\n const svg = (
    Replace me with an svg
    )\n\n return (\n <>\n
    Hello {name}!
    \n {svg}\n \n )\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} \ No newline at end of file diff --git a/langs/tr/tutorials/introduction_jsx/lesson.md b/langs/tr/tutorials/introduction_jsx/lesson.md new file mode 100644 index 00000000..c1f30b06 --- /dev/null +++ b/langs/tr/tutorials/introduction_jsx/lesson.md @@ -0,0 +1,31 @@ +JSX örneklerde gördüğümüz üzere HTML benzeri bir syntax'a sahiptir ve Solid ile bileşen oluşturmanın temelini oluşturmaktadır. +JSX `{ } ` syntax'ını kullanarak HTML üzerinde değişken ve fonksiyonları kullanabilmemize olanak sağlayan dinamik yapılar sunar. +Bu örnekte, `name` değişkenini HTML'de `{name}` şeklinde bir div'in içerisinde kullandık. Aynı şekilde, bir HTML elemanını doğrudan `svg` değişkenine atanacak şekilde ürettik. + +JSX kullanan diğer frameworklerin aksine Solid, HTML standartlarına mümkün olduğunca yakın kalmaya çalışır dolayısıyla Stack Overflow'daki yanıtlardan veya tasarımcıların şablon oluşturucularından kopyalayıp yapıştırma konusunda kolaylık sağlar. + +JSX'in HTML'i kapsayan bir superset olarak tanımlanmasını engelleyen üç ana farklılık vardır: +1. JSX'te void elemanlar yoktur. Tüm elemanların kapanış etiketine sahip olması veya kendini kapatması gerekir. Bunu `` veya `
    ` gibi yapılar kullanırken göz önünde bulundurmalısınız. +2. JSX sadece bir eleman dönmelidir. Birden çok üst seviye elemana sahip bir yapı istendiği takdirde Fragment elemanı kullanılır. + + ```jsx + <> +

    Title

    +

    Some Text

    + + ``` +3. JSX HTML yorumlarını `` veya özel etiketleri `` desteklemez. + +Fakat JSX, SVG desteklemektedir. Hadi bileşenimize doğrudan bir SVG yapıştıralım: +```jsx + + + + + + + + + Sorry but this browser does not support inline SVG. + +``` diff --git a/langs/tr/tutorials/introduction_jsx/solved.json b/langs/tr/tutorials/introduction_jsx/solved.json new file mode 100644 index 00000000..4a1bd44a --- /dev/null +++ b/langs/tr/tutorials/introduction_jsx/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\n\nfunction HelloWorld() {\n const name = \"Solid\";\n const svg = (\n \n \n \n \n \n \n \n \n Sorry but this browser does not support inline SVG.\n \n );\n\n return (\n <>\n
    Hello {name}!
    \n {svg}\n \n )\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} \ No newline at end of file diff --git a/langs/tr/tutorials/introduction_memos/lesson.json b/langs/tr/tutorials/introduction_memos/lesson.json new file mode 100644 index 00000000..cc7c690a --- /dev/null +++ b/langs/tr/tutorials/introduction_memos/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, createMemo } from 'solid-js';\n\nfunction fibonacci(num) {\n if (num <= 1) return 1;\n\n return fibonacci(num - 1) + fibonacci(num - 2);\n}\n\nfunction Counter() {\n const [count, setCount] = createSignal(10);\n const fib = () => fibonacci(count());\n\n return (\n <>\n \n
    1. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    2. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    3. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    4. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    5. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    6. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    7. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    8. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    9. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    10. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_memos/lesson.md b/langs/tr/tutorials/introduction_memos/lesson.md new file mode 100644 index 00000000..6f645b6d --- /dev/null +++ b/langs/tr/tutorials/introduction_memos/lesson.md @@ -0,0 +1,16 @@ +Genellikle, türetilmiş sinyaller (derived signal) oluşturmak yeterli olsa bile, bazen tekrarlanan işleri azaltmak için değerleri önbelleğe almak faydalı olabilir. Bir fonksiyonu değerlendirmek ve bağımlılıkları değişene kadar sonucu saklamak için memo'lar kullanılabilir. Bu sayede, başka bağımlılıklara sahip efektler için hesaplamaları önbelleğe almak veya DOM node'u oluşturmak gibi maliyetli işlemlerde, yükü azaltmak için yerinde bir çözüme ulaşılabilir. + +Memo'lar hem gözlemci - bir effect gibi -, hem de salt okunur bir sinyaldir. Hem bağımlılıkların hem de gözlemcilerinin farkındadırlar ve bu sayede herhangi bir değişiklik için yalnızca bir kez çalıştırılması sağlanır. Bu durum da onları sinyalleri değiştiren efektleri kaydederken tercih edilebilir kılar. Genel olarak, bir şey türetilebiliyorsa, türetilmelidir. + +Memo `solid-js`'ten import edeceğimiz `createMemo`'ya fonksiyonu aktararak basit bir şekilde oluşturulabilir. Örnekte, sonucu tekrar hesaplamak her tıklamada daha maliyetli hale gelmekte. Fakat fonksiyonu `createMemo` ile sardığımızda her tıklamada gerekli hesaplama sadece bir kere gerçekleşecektir: + +```jsx +const fib = createMemo(() => fibonacci(count())); +``` +`fib` fonksiyonunun içerisine `console.log` koyarak ne sıklıkla çalıştığını gözlemleyebiliriz: +```jsx +const fib = createMemo(() => { + console.log("Calculating Fibonacci"); + return fibonacci(count()); +}); +``` diff --git a/langs/tr/tutorials/introduction_memos/solved.json b/langs/tr/tutorials/introduction_memos/solved.json new file mode 100644 index 00000000..bb06d4fe --- /dev/null +++ b/langs/tr/tutorials/introduction_memos/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from 'solid-js/web';\nimport { createSignal, createMemo } from 'solid-js';\n\nfunction fibonacci(num) {\n if (num <= 1) return 1;\n\n return fibonacci(num - 1) + fibonacci(num - 2);\n}\n\nfunction Counter() {\n const [count, setCount] = createSignal(10);\n const fib = createMemo(() => {\n console.log('Calculating Fibonacci');\n return fibonacci(count());\n });\n\n return (\n <>\n \n
    1. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    2. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    3. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    4. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    5. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    6. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    7. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    8. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    9. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n
    10. {fib()} {fib()} {fib()} {fib()} {fib()}
    \n \n );\n}\n\nrender(() => , document.getElementById('app'))\n" + } + ] +} diff --git a/langs/tr/tutorials/introduction_signals/lesson.json b/langs/tr/tutorials/introduction_signals/lesson.json new file mode 100644 index 00000000..47186a77 --- /dev/null +++ b/langs/tr/tutorials/introduction_signals/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nfunction Counter() {\n return
    Count: 0
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/introduction_signals/lesson.md b/langs/tr/tutorials/introduction_signals/lesson.md new file mode 100644 index 00000000..e76ff2df --- /dev/null +++ b/langs/tr/tutorials/introduction_signals/lesson.md @@ -0,0 +1,29 @@ +_Sinyaller_ Solid'te reaktivitenin ana unsurudur. Zaman içinde değişen/değişebilen değerlerden oluşurlar; bir sinyalin değeri değiştiğinde, otomatik olarak o sinyali kullanan diğer her şey de güncellenecektir. + +Sinyal oluşturmak için `createSignal` fonksiyonunu `solid-js`'den import edelim ve Counter bileşenimizde aşağıdaki gibi çağıralım: +```jsx +const [count, setCount] = createSignal(0); +``` + +Create fonksiyonu bir argüman almaktadır ki bu da başlangıç değeridir, sonrasında getter ve setter olmak üzere iki fonksiyondan oluşan bir array döndürür. [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) ile bu fonksiyonları dilediğimiz gibi isimlendirebiliriz. Bizim durumumuzda getter'i `count` setter'i ise `setCount` olarak isimlendirelim. + +İlk döndürülen değerin bir getter (mevcut değeri döndüren bir fonksiyon) olduğunu, yani değerin kendisi olmadığına dikkat ediniz. Bunun sebebi framework'ün bu sinyalin nereden okunduğunu takip edebilmesi ve buna göre de güncellemeleri kontrol etmesidir. + +Bu derste Javascript'in `setInterval` fonksiyonu ile periyodik olarak artan bir sayaç oluşturacağız. Aşağıdaki kodu Counter bileşenimize ekleyerek `count` sinyalimizi saniyede bir güncelleyebiliriz. + +```jsx +setInterval(() => setCount(count() + 1), 1000); +``` + +Her tikte count'un bir önceki değerini okuyup, 1 ekleyip, yeni değer olarak atıyoruz. + +> Solid'de sinyaller parametre olarak fonksiyon da kabul etmektedirler, dolayısıyla bir önceki değeri, yeni değer atamak için kullanabiliriz. +> ```jsx +> setCount(c => c + 1); +> ``` + +Son olarak sinyali JSX içerisinde okumamız gerekiyor: + +```jsx +return
    Count: {count()}
    ; +``` diff --git a/langs/tr/tutorials/introduction_signals/solved.json b/langs/tr/tutorials/introduction_signals/solved.json new file mode 100644 index 00000000..266f7a15 --- /dev/null +++ b/langs/tr/tutorials/introduction_signals/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n\n setInterval(() => setCount(count() + 1), 1000);\n\n return
    Count: {count()}
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/lifecycles_oncleanup/lesson.json b/langs/tr/tutorials/lifecycles_oncleanup/lesson.json new file mode 100644 index 00000000..21ee04ad --- /dev/null +++ b/langs/tr/tutorials/lifecycles_oncleanup/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, onCleanup } from \"solid-js\";\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n\n setInterval(() => setCount(count() + 1), 1000);\n\n return
    Count: {count()}
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/lifecycles_oncleanup/lesson.md b/langs/tr/tutorials/lifecycles_oncleanup/lesson.md new file mode 100644 index 00000000..2262fefb --- /dev/null +++ b/langs/tr/tutorials/lifecycles_oncleanup/lesson.md @@ -0,0 +1,10 @@ +Bazı frameworkler temizleme (cleanup) metotlarını side-effect'lerin veya lifecycle fonksiyonlarının dönüş değerleri olarak eşleştirir/kullanır. Solid render ağacındaki her şey (muhtemelen atıl/durağan) bir Effect'in içinde yaşadığı ve iç içe geçebildiği için `onCleanup`'ı birinci sınıf bir fonksiyon haline getirdik. `onCleanup` Herhangi bir kapsamda çağrılabilir: bu kapsam yeniden değerlendirilmek (re-evaluate) için tetiklendiğinde ve son olarak kaldırıldığında çalışacaktır. + +`onCleanup`'ı bileşenlerinizde veya Effect'lerinizde kullanabilirsiniz. Özel tanımladığınız direktiflerde kullanabilirsiniz. Reaktif sistemin senkronize yürütülmesine bağlı olan hemen hemen her yerde kullanabilirsiniz. + +Eğitimin giriş bölümündeki sinyal örneği hiçbir zaman kendisini temizlemiyordu, Bu problemi `setInterval` çağrısını aşağıdaki ile değiştirerek düzeltelim: + +```js +const timer = setInterval(() => setCount(count() + 1), 1000); +onCleanup(() => clearInterval(timer)); +``` \ No newline at end of file diff --git a/langs/tr/tutorials/lifecycles_oncleanup/solved.json b/langs/tr/tutorials/lifecycles_oncleanup/solved.json new file mode 100644 index 00000000..f7fde7ca --- /dev/null +++ b/langs/tr/tutorials/lifecycles_oncleanup/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, onCleanup } from \"solid-js\";\n\nfunction Counter() {\n const [count, setCount] = createSignal(0);\n\n const timer = setInterval(() => setCount(count() + 1), 1000);\n onCleanup(() => clearInterval(timer));\n\n return
    Count: {count()}
    ;\n}\n\nrender(() => , document.getElementById('app'));" + } + ] +} diff --git a/langs/tr/tutorials/lifecycles_onmount/lesson.json b/langs/tr/tutorials/lifecycles_onmount/lesson.json new file mode 100644 index 00000000..77dd5843 --- /dev/null +++ b/langs/tr/tutorials/lifecycles_onmount/lesson.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, onMount, For } from \"solid-js\";\nimport \"./styles.css\";\n\nfunction App() {\n const [photos, setPhotos] = createSignal([]);\n\n return <>\n

    Photo album

    \n\n
    \n Loading...

    }>{ photo =>\n
    \n {photo.title}\n
    {photo.title}
    \n
    \n }
    \n
    \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "styles", + "type": "css", + "content": ".photos {\n width: 100%;\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n grid-gap: 8px;\n}\n\nfigure, img {\n width: 100%;\n margin: 0;\n}" + } + ] +} diff --git a/langs/tr/tutorials/lifecycles_onmount/lesson.md b/langs/tr/tutorials/lifecycles_onmount/lesson.md new file mode 100644 index 00000000..c1bd01b1 --- /dev/null +++ b/langs/tr/tutorials/lifecycles_onmount/lesson.md @@ -0,0 +1,16 @@ +Solid'de az sayıda Lifecycle (Yaşam Döngüsü) fonksiyonu vardır, çünkü her şey reaktif sistem içerisinde yaşar ve son bulur. Reaktif sistem senkronize şekilde oluşur ve güncellenir, bu nedenle de sadece zamanlama (scheduling) güncellemenin sonuna eklenen efektlere gelir. + +Temel görevleri yerine getiren geliştiricilerin genellikle bu şekilde düşünmediğini fark ettik ve bu yüzden +işleri kolaylaştırmak için `onMount` adında bir alias oluşturduk. `onMount` aslında, sadece takip edilmeyen (non-tracking) bir `createEffect` +çağrısıdır ve asla tekrar çağrılmaz. +Yani `onMount` initial rendering tamamlandıktan hemen sonra sadece bir kere çalışacağından emin olabileceğiniz bir effect çağrısıdır. + +`onMount` hook'unu fetch ile beraber resimleri getirmek için kullanalım: +```js +onMount(async () => { + const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`); + setPhotos(await res.json()); +}); +``` + +Yaşam döngüleri sadece tarayıcıda çalışır, dolaysıyla `onMount` içerisine kod yazmak SSR sırasında sunucuda çalışmama avantajını sağlar. Bu örnekte veri getirme (fetching) işlemi kullanmış olsak da, genellikle gerçek sunucu/tarayıcı koordinasyonu için Solid'in resource'larını kullanırız. \ No newline at end of file diff --git a/langs/tr/tutorials/lifecycles_onmount/solved.json b/langs/tr/tutorials/lifecycles_onmount/solved.json new file mode 100644 index 00000000..1638c344 --- /dev/null +++ b/langs/tr/tutorials/lifecycles_onmount/solved.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, onMount, For } from \"solid-js\";\nimport \"./styles.css\";\n\nfunction App() {\n const [photos, setPhotos] = createSignal([]);\n\n onMount(async () => {\n const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);\n setPhotos(await res.json());\n });\n\n return <>\n

    Photo album

    \n\n
    \n Loading...

    }>{ photo =>\n
    \n {photo.title}\n
    {photo.title}
    \n
    \n }
    \n
    \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "styles", + "type": "css", + "content": ".photos {\n width: 100%;\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n grid-gap: 8px;\n}\n\nfigure, img {\n width: 100%;\n margin: 0;\n}" + } + ] +} diff --git a/langs/tr/tutorials/props_children/lesson.json b/langs/tr/tutorials/props_children/lesson.json new file mode 100644 index 00000000..4d4051be --- /dev/null +++ b/langs/tr/tutorials/props_children/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, For } from \"solid-js\";\n\nimport ColoredList from \"./colored-list\";\n\nfunction App() {\n const [color, setColor] = createSignal(\"purple\");\n\n return <>\n \n {item =>
    {item}
    }
    \n
    \n \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "colored-list", + "content": "import { createEffect, children } from \"solid-js\";\n\nexport default function ColoredList(props) {\n return <>{props.children}\n}" + } + ] +} diff --git a/langs/tr/tutorials/props_children/lesson.md b/langs/tr/tutorials/props_children/lesson.md new file mode 100644 index 00000000..d7b727bf --- /dev/null +++ b/langs/tr/tutorials/props_children/lesson.md @@ -0,0 +1,33 @@ +Solid'i bu kadar performanslı yapan şeylerden birisi de bileşenlerin temelde sadece fonksiyon çağrısı olmasıdır. Solid'te güncellemelerin yayılması, derleyicinin potansiyel olarak reaktif ifadeleri obje getter'larına sarması ile olur. Derleyicinin çıktısını aşağıdaki gibi düşünebilirsiniz: + +```jsx +// aşağıdaki JSX + + + + +// buna dönüşmekte +MyComp({ + get dynamic() { return mySignal() }, + get children() { return Child() } +}); +``` +Yani props lazy olarak değerlendirilir (lazily evaluate edilir). Yani kullanılacakları ana kadar bir erişim gerçekleşmez. Bu sayede, ek wrapper veya senkronizasyon olmaksızın reaktivite korunur. Ancak bu durum; tekrarlı erişimin, alt bileşenlerin veya elemanların yeniden oluşturulmasına yol açabileceği anlamına gelir. + +Genellikle JSX'e sadece prop'lar ekleneceği için sorun oluşmamaktadır ancak, child (alt) elemanlarla çalışırken, elemanları defalarca tekrar oluşturmaktan kaçınmak için dikkatli olmanız gerekir. + +Bu sebeple, Solid `children` helper'ını sunar. Bu metot hem `children` prop'u etrafında bir memo oluşturur hem de iç içe geçmiş child reactive referanslarını çözer, böylece child'lar ile doğrudan etkileşime girilebilir. + +Örneğimizde, dinamik bir listemiz var ve elemanların `color` style property'sini ayarlamak ayarlamak istiyoruz. Doğrudan `props.children` ile etkileşime girersek, yalnızca node'ları defalarca oluşturmakla kalmaz, aynı zamanda da `props.children`'i ``'dan döndürülen memo gibi bir fonksiyon olarak bulurduk. + +Bunun yerine `children` helper'ını `colored-list.tsx` içerisinde kullanalım: +```jsx +export default function ColoredList(props) { + const c = children(() => props.children); + return <>{c()} +} +``` +Şimdi de elemanlarımızı güncelleyecek bir Effect oluşturalım: +```jsx +createEffect(() => c().forEach(item => item.style.color = props.color)); +``` diff --git a/langs/tr/tutorials/props_children/solved.json b/langs/tr/tutorials/props_children/solved.json new file mode 100644 index 00000000..7f7aa8d5 --- /dev/null +++ b/langs/tr/tutorials/props_children/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, For } from \"solid-js\";\n\nimport ColoredList from \"./colored-list\";\n\nfunction App() {\n const [color, setColor] = createSignal(\"purple\");\n\n return <>\n \n {item =>
    {item}
    }
    \n
    \n \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "colored-list", + "content": "import { createEffect, children } from \"solid-js\";\n\nexport default function ColoredList(props) {\n const c = children(() => props.children);\n createEffect(() => c().forEach(item => item.style.color = props.color));\n return <>{c()}\n}" + } + ] +} diff --git a/langs/tr/tutorials/props_defaults/lesson.json b/langs/tr/tutorials/props_defaults/lesson.json new file mode 100644 index 00000000..671b1e57 --- /dev/null +++ b/langs/tr/tutorials/props_defaults/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport Greeting from \"./greeting\";\n\nfunction App() {\n const [name, setName] = createSignal();\n\n return <>\n \n \n \n \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "greeting", + "content": "import { mergeProps } from \"solid-js\";\n\nexport default function Greeting(props) {\n return

    {props.greeting || \"Hi\"} {props.name || \"John\"}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/props_defaults/lesson.md b/langs/tr/tutorials/props_defaults/lesson.md new file mode 100644 index 00000000..8100f377 --- /dev/null +++ b/langs/tr/tutorials/props_defaults/lesson.md @@ -0,0 +1,13 @@ +Props, bileşen fonksiyonumuza aktarılabilen, JSX'e bağlı tüm attribute'ları temsil eden objeye verdiğimiz isimdir. Props objeleri salt okunurdur ve Object getter'larına sarılmış reaktif özelliklere sahiplerdir. sayede, çağıranın sinyal, sinyal ifadesi veya statik değer kullanmasına bağlı olmadan tutarlı bir biçimde olmalarını sağlanır. Ulaşmak için `props.propName` kullanılır. + +Bu nedenle props objelerini yalnızca destructure ederek kullanmamak önemlidir, çünkü, bu bir izlenme kapsamı içerisinde yapılmazsa reaktivite kaybolacaktır. Genel olarak, props objesi üzerindeki property'lere özellikle Solid'in primitifleri veya JSX dışında erişmek reaktiviteyi kaybetmekle sonuçlanabilir. Bu sadece destructing için değil, aynı zamanda `Object.assign` gibi spread ve fonksiyonlar için de geçerlidir. + +Solid, props ile çalışırken bize yardımcı olacak bazı utility'lere sahiptir. Bunlardan birincisi, potansiyel olarak reaktif objeleri reaktiviteyi kaybetmeden birleştiren `mergeProps`tur. (`Object.assign` benzeri). En yaygın kullanımı bileşenlerimiz için varsayılan prop'ları atamaktır. + +Örneğimizde, `greetings.tsx` dosyasında varsayılanları satır içinde kullandık, ek olarak `mergeProps`'u da kullanarak, reaktiviteyi koruyabilir ve güncellemelerin işlenmesini sağlayabiliriz. + +```jsx +const merged = mergeProps({ greeting: "Hi", name: "John" }, props); + +return

    {merged.greeting} {merged.name}

    +``` diff --git a/langs/tr/tutorials/props_defaults/solved.json b/langs/tr/tutorials/props_defaults/solved.json new file mode 100644 index 00000000..17361fc1 --- /dev/null +++ b/langs/tr/tutorials/props_defaults/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport Greeting from \"./greeting\";\n\nfunction App() {\n const [name, setName] = createSignal();\n\n return <>\n \n \n \n \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "greeting", + "content": "import { mergeProps } from \"solid-js\";\n\nexport default function Greeting(props) {\n const merged = mergeProps({ greeting: \"Hi\", name: \"John\" }, props);\n\n return

    {merged.greeting} {merged.name}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/props_split/lesson.json b/langs/tr/tutorials/props_split/lesson.json new file mode 100644 index 00000000..0439f16a --- /dev/null +++ b/langs/tr/tutorials/props_split/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport Greeting from \"./greeting\";\n\nfunction App() {\n const [name, setName] = createSignal(\"Jakob\");\n\n return <>\n \n \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "greeting", + "content": "import { splitProps } from \"solid-js\";\n\nexport default function Greeting(props) {\n const { greeting, name, ...others } = props;\n return

    {greeting} {name}

    \n}" + } + ] +} diff --git a/langs/tr/tutorials/props_split/lesson.md b/langs/tr/tutorials/props_split/lesson.md new file mode 100644 index 00000000..3bdf4d9c --- /dev/null +++ b/langs/tr/tutorials/props_split/lesson.md @@ -0,0 +1,23 @@ +Props için birleştirme işlemi haricinde de yapmak istediğimiz işlemler olacaktır. + +Genellikle, props gruplara ayrılır ki +gerekenler mevcut bileşende kullanılsın ve diğerleri de alt bileşenlere aktarılsın. + +Bu kullanım için Solid [`splitProps`](/docs/latest/api#splitprops) fonksiyonuna sahiptir. Argüman olarak props objesini ve kendi props objesine çıkarmak istediğimiz bir veya daha fazla anahtar array'leri alır. Belirtilen anahtarlardaki her bir array için bir tane olmak üzere props objelerinden oluşan bir array, ve kalan anahtarlar ile de bir props objesi döner. Döndürülen bütün objeler reaktivitiyi korumaktadır. + +Örneğimiz isim belirlesek de güncellenmiyor, çünkü reaktivite `greeting.tsx` i destructure ederken kaybedilmiş: +```jsx +export default function Greeting(props) { + const { greeting, name, ...others } = props; + return

    {greeting} {name}

    +} +``` + +Bunun yerine `splitProps` ile reaktiviteyi bu şekilde koruyabiliriz: +```jsx +export default function Greeting(props) { + const [local, others] = splitProps(props, ["greeting", "name"]); + return

    {local.greeting} {local.name}

    +} +``` +Artık buton beklediğimiz gibi çalışıyor. \ No newline at end of file diff --git a/langs/tr/tutorials/props_split/solved.json b/langs/tr/tutorials/props_split/solved.json new file mode 100644 index 00000000..a6026a0e --- /dev/null +++ b/langs/tr/tutorials/props_split/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal } from \"solid-js\";\n\nimport Greeting from \"./greeting\";\n\nfunction App() {\n const [name, setName] = createSignal(\"Jakob\");\n\n return <>\n \n \n ;\n}\n\nrender(() => , document.getElementById('app'));" + }, + { + "name": "greeting", + "content": "import { splitProps } from \"solid-js\";\n\nexport default function Greeting(props) {\n const [local, others] = splitProps(props, [\"greeting\", \"name\"]);\n return

    {local.greeting} {local.name}

    \n}" + } + ] +} \ No newline at end of file diff --git a/langs/tr/tutorials/reactivity_batch/lesson.json b/langs/tr/tutorials/reactivity_batch/lesson.json new file mode 100644 index 00000000..29a90329 --- /dev/null +++ b/langs/tr/tutorials/reactivity_batch/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, batch } from \"solid-js\";\n\nconst App = () => {\n const [firstName, setFirstName] = createSignal(\"John\");\n const [lastName, setLastName] = createSignal(\"Smith\");\n const fullName = () => {\n console.log(\"Running FullName\");\n return `${firstName()} ${lastName()}`\n } \n const updateNames = () => {\n console.log(\"Button Clicked\");\n setFirstName(firstName() + \"n\");\n setLastName(lastName() + \"!\");\n }\n \n return \n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/reactivity_batch/lesson.md b/langs/tr/tutorials/reactivity_batch/lesson.md new file mode 100644 index 00000000..9a23e7cf --- /dev/null +++ b/langs/tr/tutorials/reactivity_batch/lesson.md @@ -0,0 +1,16 @@ +Solid'in reaktivitesi synchronous'tur, yani DOM herhangi bir değişiklikten sonraki satırda güncellenmiş hale gelir. Solid'in granular rendering'i sadece reaktif sistemdeki güncellemenin bir yayılımı olduğu için bu çoğunlukla mükemmeldir. İlişkisi bulunmayan değişikliklerin iki kez "render edilmesi" aslında bunun boşuna olduğu anlamına gelmez. + +Peki ya değişiklikler arasına ilişki varsa? Solid'in `batch` helper'i birden fazla değişikliği sıraya koymaya ve gözlemcilerine bildirmeden önce hepsini aynı anda uygulamaya izin verir. + +Örneğimizde, bir butona tıklandığında her iki ismi de atıyoruz ve bu, işlenen render'lanmış güncellemeyi iki kez tetikliyor. Butona tıkladığınızda log'ları konsolda görebilirsiniz. Öyleyse `set` çağrılarını bir `batch` içerisine saralım. + +```js + const updateNames = () => { + console.log("Button Clicked"); + batch(() => { + setFirstName(firstName() + "n"); + setLastName(lastName() + "!"); + }) + } +``` +Ve bu kadar, bütün değişiklikler artık bir kere bildiriliyor. \ No newline at end of file diff --git a/langs/tr/tutorials/reactivity_batch/solved.json b/langs/tr/tutorials/reactivity_batch/solved.json new file mode 100644 index 00000000..bf41d10a --- /dev/null +++ b/langs/tr/tutorials/reactivity_batch/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, batch } from \"solid-js\";\n\nconst App = () => {\n const [firstName, setFirstName] = createSignal(\"John\");\n const [lastName, setLastName] = createSignal(\"Smith\");\n const fullName = () => {\n console.log(\"Running FullName\");\n return `${firstName()} ${lastName()}`\n } \n const updateNames = () => {\n console.log(\"Button Clicked\");\n batch(() => {\n setFirstName(firstName() + \"n\");\n setLastName(lastName() + \"!\");\n })\n }\n \n return \n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/reactivity_on/lesson.json b/langs/tr/tutorials/reactivity_on/lesson.json new file mode 100644 index 00000000..22900826 --- /dev/null +++ b/langs/tr/tutorials/reactivity_on/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, createEffect, on } from \"solid-js\";\n\nconst App = () => {\n const [a, setA] = createSignal(1);\n const [b, setB] = createSignal(1);\n\n createEffect(() => {\n console.log(a(), b());\n });\n\n return <>\n \n \n \n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/reactivity_on/lesson.md b/langs/tr/tutorials/reactivity_on/lesson.md new file mode 100644 index 00000000..15a7e3ae --- /dev/null +++ b/langs/tr/tutorials/reactivity_on/lesson.md @@ -0,0 +1,9 @@ +Kolaylık sağlamak için Solid, hesaplamalarımız için spesifik bağımlılıklar oluşturmayı sağlayan bir `on` helper'ına sahiptir. Bu çoğunlukla hangi Sinyallerin takip edileceği konusunda daha da açık olmanın (ve okunsalar bile diğer sinyalleri track etmemenin) kısa bir yolu olarak kullanılır. Ayrıca `on` hesaplamanın hemen yürütülmesini ve yalnızca ilk değişiklikte çalıştırılmasını sağlayan bir `defer` seçeneği sunar. + +Örneğimizde, Effect'in yalnızca `a` değeri güncellendiğinde çalışmasını ve bu değer değişene kadar çalışmayı ertelemesini sağlayalım: + +```js +createEffect(on(a, (a) => { + console.log(a, b()); +}, { defer: true })); +``` diff --git a/langs/tr/tutorials/reactivity_on/solved.json b/langs/tr/tutorials/reactivity_on/solved.json new file mode 100644 index 00000000..21608f91 --- /dev/null +++ b/langs/tr/tutorials/reactivity_on/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, createEffect, on } from \"solid-js\";\n\nconst App = () => {\n const [a, setA] = createSignal(1);\n const [b, setB] = createSignal(1);\n\n createEffect(on(a, (a) => {\n console.log(a, b());\n }, { defer: true }));\n\n return <>\n \n \n \n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/reactivity_untrack/lesson.json b/langs/tr/tutorials/reactivity_untrack/lesson.json new file mode 100644 index 00000000..01a332e0 --- /dev/null +++ b/langs/tr/tutorials/reactivity_untrack/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, createEffect, untrack } from \"solid-js\";\n\nconst App = () => {\n const [a, setA] = createSignal(1);\n const [b, setB] = createSignal(1);\n\n createEffect(() => {\n console.log(a(), b());\n });\n\n return <>\n \n \n \n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/reactivity_untrack/lesson.md b/langs/tr/tutorials/reactivity_untrack/lesson.md new file mode 100644 index 00000000..e81ae7de --- /dev/null +++ b/langs/tr/tutorials/reactivity_untrack/lesson.md @@ -0,0 +1,12 @@ +Bazen reaktif bir Context içinde olsa bile Signal okumalarının track edilmemesi istenilebilir. Solid, `untrack` helper'i ile sarılmış işlemlerin okumaları track etmesini engelleyebilir. + +Örneğimizde `b` değiştiğinde loglamak istemediğimizi varsayalım. Signal'i aşağıdaki şekilde değiştirerek `b` sinyalinin takibini kaldırabiliriz (untrack). + +```js +createEffect(() => { + console.log(a(), untrack(b)); +}); +``` +Sinyaller fonksiyon olduğu için doğrudan aktarılabilirler, ancak `untrack` daha karmaşık davranışa sahip fonksiyonları da sarabilir. + +`untrack` okumaların izlenmesini devre dışı bırakıyor olsa da, hala gerçekleşen ve gözlemcilerini bildiren yazmalar üzerinde hiçbir etkisi yoktur. diff --git a/langs/tr/tutorials/reactivity_untrack/solved.json b/langs/tr/tutorials/reactivity_untrack/solved.json new file mode 100644 index 00000000..0f66193d --- /dev/null +++ b/langs/tr/tutorials/reactivity_untrack/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { createSignal, createEffect, untrack } from \"solid-js\";\n\nconst App = () => {\n const [a, setA] = createSignal(1);\n const [b, setB] = createSignal(1);\n\n createEffect(() => {\n console.log(a(), untrack(b));\n });\n\n return <>\n \n \n \n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_context/lesson.json b/langs/tr/tutorials/stores_context/lesson.json new file mode 100644 index 00000000..5c8d5014 --- /dev/null +++ b/langs/tr/tutorials/stores_context/lesson.json @@ -0,0 +1,16 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport Nested from \"./nested\";\nimport { CounterProvider } from \"./counter\";\n\nfunction App() {\n return <>\n

    Welcome to Counter App

    \n \n \n};\n\nrender(() => , document.getElementById(\"app\"));" + }, + { + "name": "nested", + "content": "import { useCounter } from \"./counter\";\n\nexport default function Nested() {\n return (\n <>\n
    0
    \n \n \n \n );\n};" + }, + { + "name": "counter", + "content": "import { createSignal, createContext, useContext } from \"solid-js\";\n\nconst CounterContext = createContext();\n\nexport function CounterProvider(props) {\n const [count, setCount] = createSignal(props.count || 0),\n counter = [\n count,\n {\n increment() {\n setCount(c => c + 1);\n },\n decrement() {\n setCount(c => c - 1);\n }\n }\n ];\n\n return (\n \n {props.children}\n \n );\n}\n\nexport function useCounter() { return useContext(CounterContext); }" + } + ] +} diff --git a/langs/tr/tutorials/stores_context/lesson.md b/langs/tr/tutorials/stores_context/lesson.md new file mode 100644 index 00000000..2a0ba973 --- /dev/null +++ b/langs/tr/tutorials/stores_context/lesson.md @@ -0,0 +1,28 @@ +Solid verileri props olarak geçirmeye gerek olmaksızın aktarmak için bir Context API sağlar. Bu, sinyalleri ve store'ları paylaşmak için kullanışlı olabilir. Context kullanımı, reaktif sistemin bir parçası olarak oluşturulma ve sistem tarafından yönetilme avantajına sahiptir. + +Başlamak için bir Context objesini oluşturuyoruz. Bu obje, verilerimizi enjekte etmek için kullanılan bir `Provider` bileşeni içerir. Bununla birlikte, `Provider` bileşenlerini ve `useContext` consumer'ların belirli Context için önceden yapılandırılmış sürümleri ile sarmak yaygın bir kullanımdır. + +Bu derste de tam olarak bunu yapıyoruz. Basit bir counter (sayaç) store'unun tanımını `counter.tsx` dosyasında görebilirsiniz. + +Context'i kullanmak için öncelikle App bileşenimizi global olarak sağlamak üzere saralım. Sarmaladığımız `CounterProvider`'ı kullanacağız. Son olarak count'u başlangıç değeri 1 olacak şekilde düzenleyelim. + +```jsx +render(() => ( + + + +), document.getElementById("app")); +``` + +Sonra, `nested.tsx` bileşenimizdeki counter context'ini consume etmemiz gerekiyor. Bunu, sarılmış `useCounter` consumer'ini kullanarak yapabiliriz: + +```jsx +const [count, { increment, decrement }] = useCounter(); +return ( + <> +
    {count()}
    + + + +); +``` \ No newline at end of file diff --git a/langs/tr/tutorials/stores_context/solved.json b/langs/tr/tutorials/stores_context/solved.json new file mode 100644 index 00000000..c5967806 --- /dev/null +++ b/langs/tr/tutorials/stores_context/solved.json @@ -0,0 +1,16 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport Nested from \"./nested\";\nimport { CounterProvider } from \"./counter\";\n\nfunction App() {\n return <>\n

    Welcome to Counter App

    \n \n \n};\n\nrender(() => (\n \n \n \n), document.getElementById(\"app\"));" + }, + { + "name": "nested", + "content": "import { useCounter } from \"./counter\";\n\nexport default function Nested() {\n const [count, { increment, decrement }] = useCounter();\n return (\n <>\n
    {count()}
    \n \n \n \n );\n};" + }, + { + "name": "counter", + "content": "import { createSignal, createContext, useContext } from \"solid-js\";\n\nconst CounterContext = createContext();\n\nexport function CounterProvider(props) {\n const [count, setCount] = createSignal(props.count || 0),\n counter = [\n count,\n {\n increment() {\n setCount(c => c + 1);\n },\n decrement() {\n setCount(c => c - 1);\n }\n }\n ];\n\n return (\n \n {props.children}\n \n );\n}\n\nexport function useCounter() { return useContext(CounterContext); }" + } + ] +} diff --git a/langs/tr/tutorials/stores_createstore/lesson.json b/langs/tr/tutorials/stores_createstore/lesson.json new file mode 100644 index 00000000..9a867b74 --- /dev/null +++ b/langs/tr/tutorials/stores_createstore/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { For, createSignal } from \"solid-js\";\nimport { createStore } from \"solid-js/store\";\n\nconst App = () => {\n let input;\n let todoId = 0;\n const [todos, setTodos] = createSignal([])\n const addTodo = (text) => {\n setTodos([...todos(), { id: ++todoId, text, completed: false }]);\n }\n const toggleTodo = (id) => {\n setTodos(todos().map((todo) => (\n todo.id !== id ? todo : { ...todo, completed: !todo.completed }\n )));\n }\n\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n \n
    \n \n {(todo) => {\n const { id, text } = todo;\n console.log(`Creating ${text}`)\n return
    \n \n {text}\n
    \n }}\n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_createstore/lesson.md b/langs/tr/tutorials/stores_createstore/lesson.md new file mode 100644 index 00000000..26f7c0b5 --- /dev/null +++ b/langs/tr/tutorials/stores_createstore/lesson.md @@ -0,0 +1,30 @@ +Store'lar Sold'in iç içe geçmiş reaktiviteye cevabıdır. Property'leri takip edilebilen proxy objelerdir ve başka objeler içerebilirler. İçerdiği objeler de otomatik olarak proxy ile sarılır. + +İşleri hafif tutmak için Solid, yalnızca izleme kapsamları altında erişilen property'ler için temel sinyaller oluşturur. Bu sayede Store'lardaki tüm sinyaller istenildiği gibi lazy şekilde oluşturulur. + +`createStore` fonksiyonu, başlangıç değeri alır ve sinyallere benzer bir okuma/yazma tuple'ı döndürür. İlk eleman salt okunur store proxy'sidir, ikinci ise bir setter fonksiyonudur. + +Setter fonksiyonu en temel haliyle, property'leri mevcut durumla birleşecek olan bir obje alır. Ayrıca iç içe güncellemeler yapabilmemiz için bir path syntax'ı da destekler. Bu sayede hem reaktivitenin kontrolünü koruyabilir, hem de nokta atışı güncellemeler yapabiliriz. + +> Sold'in path syntax'ının bir çok formu vardır ve yineleme ve aralıklar yapmak için bazı güçlü syntax'lar içerir. Tüm kapsamını görmek için API dokümantasyonuna bakın. + +Let's look at how much easier it is to achieve nested reactivity with a Store. We can replace the initialization of our component with this: +Gelin Store ile iç içe geçmiş reaktifliğin ne kadar kolay oluşturulduğuna bakalım. Bileşenimizdeki ilgili kısmı değiştirelim: + +```js +const [todos, setTodos] = createStore([]); +const addTodo = (text) => { + setTodos([...todos, { id: ++todoId, text, completed: false }]); +}; +const toggleTodo = (id) => { + setTodos( + (todo) => todo.id === id, + "completed", + (completed) => !completed + ); +}; +``` + +Store'un path syntax'ını önceki state'i almamıza ve iç içe geçmiş değerlerde yeni state'i döndürmemizi olanak tanıyan fonksiyon setter'lar ile kullanıyoruz. + +Ve hepsi bu kadar, şablonun geri kalanı da tepki verecektir (onay kutusunu tıklandığında Konsolu kontrol edin) \ No newline at end of file diff --git a/langs/tr/tutorials/stores_createstore/solved.json b/langs/tr/tutorials/stores_createstore/solved.json new file mode 100644 index 00000000..c0bf15e6 --- /dev/null +++ b/langs/tr/tutorials/stores_createstore/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js\/web\";\nimport { For } from \"solid-js\";\nimport { createStore } from \"solid-js\/store\";\n\nconst App = () => {\n let input;\n let todoId = 0;\n const [todos, setTodos] = createStore([]);\n\n const addTodo = (text) => {\n setTodos([...todos, { id: ++todoId, text, completed: false }]);\n }\n\n const toggleTodo = (id) => {\n setTodos(todo => todo.id === id, \"completed\", completed => !completed);\n }\n\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n <\/button>\n <\/div>\n \n {(todo) => {\n const { id, text } = todo;\n console.log(`Creating ${text}`)\n return
    \n \n {text}<\/span>\n <\/div>\n }}\n <\/For>\n <\/>\n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_immutable/lesson.json b/langs/tr/tutorials/stores_immutable/lesson.json new file mode 100644 index 00000000..509de763 --- /dev/null +++ b/langs/tr/tutorials/stores_immutable/lesson.json @@ -0,0 +1,20 @@ +{ + "files": [ + { + "name": "main", + "content": "// @ts-nocheck\nimport { render } from \"solid-js/web\";\nimport { For } from \"solid-js\";\n\nimport useRedux from \"./useRedux\";\nimport reduxStore from \"./store\";\nimport actions from \"./actions\";\n\nconst App = () => {\n const [store, { addTodo, toggleTodo }] = useRedux(\n reduxStore,\n actions\n );\n let input;\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n \n
    \n \n {(todo) => {\n const { id, text } = todo;\n console.log(\"Create\", text)\n return
    \n \n {text}\n
    \n }}\n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + }, + { + "name": "useRedux", + "content": "import { onCleanup } from \"solid-js\";\nimport { createStore, reconcile } from \"solid-js/store\";\n\nexport default function useRedux(store, actions) {\n const [state, setState] = createStore(store.getState());\n const unsubscribe = store.subscribe(\n () => setState(store.getState())\n );\n onCleanup(() => unsubscribe());\n return [\n state,\n mapActions(store, actions)\n ];\n};\n\nfunction mapActions(store, actions) {\n const mapped = {};\n for (const key in actions) {\n mapped[key] = (...args) => store.dispatch(actions[key](...args));\n }\n return mapped;\n}\n" + }, + { + "name": "actions", + "content": "let nextTodoId = 0;\nexport default {\n addTodo: text => ({ type: \"ADD_TODO\", id: ++nextTodoId, text }),\n toggleTodo: id => ({ type: \"TOGGLE_TODO\", id })\n};\n" + }, + { + "name": "store", + "content": "// @ts-nocheck\nimport { createStore } from 'redux';\n\n// todos reducer\nconst todos = (state = { todos: [] }, action) => {\n switch (action.type) {\n case \"ADD_TODO\":\n return { todos: [\n ...state.todos,\n {\n id: action.id,\n text: action.text,\n completed: false\n }\n ]};\n case \"TOGGLE_TODO\":\n return { todos: state.todos.map(todo => \n todo.id === action.id ? { ...todo, completed: !todo.completed } : todo\n )};\n default:\n return state;\n }\n};\n\nexport default createStore(todos);\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_immutable/lesson.md b/langs/tr/tutorials/stores_immutable/lesson.md new file mode 100644 index 00000000..5a83ada8 --- /dev/null +++ b/langs/tr/tutorials/stores_immutable/lesson.md @@ -0,0 +1,43 @@ +Store'lar çoğunlukla Solid'in Store proxy'leri kullanılarak oluşturulur. Bazen Redux, Apollo veya XState gibi immutable kütüphaneler ile interface'ler oluşturmak isteyebilirsiniz ve bunlar için parçalı (granular) güncellemeler yapmanız gerekir. + +Örneğimizde `useRedux.tsx` dosyasında görebileceğiniz temel bir Redux wrapper'ımız var. Store tanımı ve action'lar da diğer dosyalarda yer almakta. + +Temel kullanım, bir store objesi oluşturmamız ve güncelleme sırasında durumu güncellemek için Redux Store'una subscribe olmamızdır. + +```js +const [state, setState] = createStore(store.getState()); +const unsubscribe = store.subscribe( + () => setState(store.getState()) +); +``` +Demo'da ögelerin eklenmesi veya işaretlenmesi iyi çalışır gibi görünüyor. Ancak, verimsiz render'lar yok sayılmamalıdır. Dikkat ederseniz console.log sadece öge eklendiğinde değil ögeler işaretlendiğinde de oluşmakta. + +Bunun nedeni Solid'in varsayılan olarak farklılaşmıyor (diff) oluşudur. Yeni ögenin yeni olduğunu varsayar ve değiştirir. Veriler parçalı değişiyorsa farklılaştırmaya gerek olmaz. Ama ya gerekirse? + +Solid, `setStore` çağrısını geliştiren ve bu immutable kaynaklardan gelen verileri yalnızca parçalı güncellemeleri bildirerek farklılaştırmamızı sağlayan bir yöntem olarak `reconcile` fonksiyonunu sağlar. + +Let's update that code to: +```js +const [state, setState] = createStore(store.getState()); +const unsubscribe = store.subscribe( + () => setState(reconcile(store.getState())) +); +``` +Şimdi örneğimizde beklediğimiz gibi Create sadece öğe eklenirken konsol'da yazdırılıyor. + +Tek çözüm elbette bu değil, bazı framework'lerde `key` property'sinin döngü içerisindeki elemanlarda kullanıldığını görmüşsünüzdür. Sorun şu ki, bu davranışı varsayılan hale getirdiğinizde, her zaman liste hesaplaması yapmanız ve derlenmiş framework'lerde bile, olası değişiklikler için tüm alt elemanları her zaman farklılaştırmanız gerekir. Veri merkezli bir yaklaşım, bunu yalnızca template dışı uygulanabilir hale getirmez aynı zamanda da daha tercih edilebilir hale getirir. Internal state yönetiminin buna ihtiyaç duymadığını da göz önünde bulundurduğumuzda, Solid'in en performanslı yolu varsayılan olarak sunduğunu unutmayalım. + +Elbette, ihtiyaç duyulduğunda `reconcile` kullanmakta bir sorun yoktur. Bazen basit bir reducer, veri güncellemelerini organize etmek için harika bir yöntem sağlayabilir. `reconcile` kendini burada gösterir ve kendi `useReducer` primitiflerinizi oluşturur. + +```js +const useReducer = (reducer, state) => { + const [store, setStore] = createStore(state); + const dispatch = (action) => { + state = reducer(state, action); + setStore(reconcile(state)); + } + return [store, dispatch]; +}; +``` + +`Reconcile`'ın davranışı yapılandırılabilir. Özel bir key ayarlanabilir, ayrıca yapısal klonlamayı yok sayan ve yalnızca alt parçaları (leaves) farklılaştıran bir birleştirme seçeneği de vardır. \ No newline at end of file diff --git a/langs/tr/tutorials/stores_immutable/solved.json b/langs/tr/tutorials/stores_immutable/solved.json new file mode 100644 index 00000000..5ac5aa45 --- /dev/null +++ b/langs/tr/tutorials/stores_immutable/solved.json @@ -0,0 +1,20 @@ +{ + "files": [ + { + "name": "main", + "content": "// @ts-nocheck\nimport { render } from \"solid-js/web\";\nimport { For } from \"solid-js\";\n\nimport useRedux from \"./useRedux\";\nimport reduxStore from \"./store\";\nimport actions from \"./actions\";\n\nconst App = () => {\n const [store, { addTodo, toggleTodo }] = useRedux(\n reduxStore,\n actions\n );\n let input;\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n \n
    \n \n {(todo) => {\n const { id, text } = todo;\n console.log(\"Create\", text)\n return
    \n \n {text}\n
    \n }}\n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + }, + { + "name": "useRedux", + "content": "import { onCleanup } from \"solid-js\";\nimport { createStore, reconcile } from \"solid-js/store\";\n\nexport default function useRedux(store, actions) {\n const [state, setState] = createStore(store.getState());\n const unsubscribe = store.subscribe(\n () => setState(reconcile(store.getState()))\n );\n onCleanup(() => unsubscribe());\n return [\n state,\n mapActions(store, actions)\n ];\n};\n\nfunction mapActions(store, actions) {\n const mapped = {};\n for (const key in actions) {\n mapped[key] = (...args) => store.dispatch(actions[key](...args));\n }\n return mapped;\n}\n" + }, + { + "name": "actions", + "content": "let nextTodoId = 0;\nexport default {\n addTodo: text => ({ type: \"ADD_TODO\", id: ++nextTodoId, text }),\n toggleTodo: id => ({ type: \"TOGGLE_TODO\", id })\n};\n" + }, + { + "name": "store", + "content": "// @ts-nocheck\nimport { createStore } from 'redux';\n\n// todos reducer\nconst todos = (state = { todos: [] }, action) => {\n switch (action.type) {\n case \"ADD_TODO\":\n return { todos: [\n ...state.todos,\n {\n id: action.id,\n text: action.text,\n completed: false\n }\n ]};\n case \"TOGGLE_TODO\":\n return { todos: state.todos.map(todo => \n todo.id === action.id ? { ...todo, completed: !todo.completed } : todo\n )};\n default:\n return state;\n }\n};\n\nexport default createStore(todos);\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_mutation/lesson.json b/langs/tr/tutorials/stores_mutation/lesson.json new file mode 100644 index 00000000..c0bf15e6 --- /dev/null +++ b/langs/tr/tutorials/stores_mutation/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js\/web\";\nimport { For } from \"solid-js\";\nimport { createStore } from \"solid-js\/store\";\n\nconst App = () => {\n let input;\n let todoId = 0;\n const [todos, setTodos] = createStore([]);\n\n const addTodo = (text) => {\n setTodos([...todos, { id: ++todoId, text, completed: false }]);\n }\n\n const toggleTodo = (id) => {\n setTodos(todo => todo.id === id, \"completed\", completed => !completed);\n }\n\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n <\/button>\n <\/div>\n \n {(todo) => {\n const { id, text } = todo;\n console.log(`Creating ${text}`)\n return
    \n \n {text}<\/span>\n <\/div>\n }}\n <\/For>\n <\/>\n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_mutation/lesson.md b/langs/tr/tutorials/stores_mutation/lesson.md new file mode 100644 index 00000000..e392cca8 --- /dev/null +++ b/langs/tr/tutorials/stores_mutation/lesson.md @@ -0,0 +1,23 @@ +Solid şiddetle shallow immutable modellerin kullanmasını tavsiye eder. Okumaları ve yazmaları ayırarak, bileşen katmanlarından geçerken proxy'mizdeki değişkenlerin izini kaybetme riski olmadan sistemimizin reaktivitesi üzerinde daha iyi kontrol sağlarız. Sinyallere kıyasla Store'larda bu kullanımın getirisi çok daha yüksek olacaktır. + +Ancak bazen mutation'ları kullanmak, daha doğrusu mutation'lar kullanıyormuş gibi mantık yürütmek daha kolaydır. Bu nedenle Solid, `setStore` çağrıları içinde Store objesinin yazılabilir bir proxy sürümünü mutate edebilmenize olanak tanıyan Immer'den ilham alan bir `produce` store değiştiricisi sunar. + +`produce`, kontrolü elden bırakmadan küçük mutate alanlarına izin vermek için güzel bir araçtır. Event handler'ı şu şekilde değiştirerek `produce`'u Todo örneğimizde kullanalım: + +```jsx +const addTodo = (text) => { + setTodos( + produce((todos) => { + todos.push({ id: ++todoId, text, completed: false }); + }) + ); +}; +const toggleTodo = (id) => { + setTodos( + (todo) => todo.id === id, + produce((todo) => (todo.completed = !todo.completed)) + ); +}; +``` + +Store ve `produce` kullanımların bir çoğu için yeterli olacaktır, Solid ayrıca `createMutable` ile kullanılabilen bir mutable Store objesine sahiptir. Internal API'lar için önerilen bir yaklaşım olmasa da bazen interop veya 3. parti sistemlerle uyumluluk için kullanışlı olacaktır. diff --git a/langs/tr/tutorials/stores_mutation/solved.json b/langs/tr/tutorials/stores_mutation/solved.json new file mode 100644 index 00000000..3f3926d9 --- /dev/null +++ b/langs/tr/tutorials/stores_mutation/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "\/\/ @ts-nocheck\r\nimport { render, For } from \"solid-js\/web\";\r\nimport { createStore, produce } from \"solid-js\/store\";\r\n\r\nconst App = () => {\r\n let input;\r\n let todoId = 0;\r\n const [todos, setTodos] = createStore([]);\r\n const addTodo = (text) => {\r\n setTodos(\r\n produce((todos) => {\r\n todos.push({ id: ++todoId, text, completed: false });\r\n }),\r\n );\r\n };\r\n const toggleTodo = (id) => {\r\n setTodos(\r\n todo => todo.id === id,\r\n produce((todo) => (todo.completed = !todo.completed)),\r\n );\r\n };\r\n\r\n return (\r\n <>\r\n
    \r\n \r\n {\r\n if (!input.value.trim()) return;\r\n addTodo(input.value);\r\n input.value = \"\";\r\n }}\r\n >\r\n Add Todo\r\n <\/button>\r\n <\/div>\r\n \r\n {(todo) => {\r\n const { id, text } = todo;\r\n console.log(`Creating ${text}`)\r\n return
    \r\n \r\n {text}<\/span>\r\n <\/div>\r\n }}\r\n <\/For>\r\n <\/>\r\n );\r\n};\r\n\r\nrender(App, document.getElementById(\"app\"));" + } + ] +} diff --git a/langs/tr/tutorials/stores_nested_reactivity/lesson.json b/langs/tr/tutorials/stores_nested_reactivity/lesson.json new file mode 100644 index 00000000..32f03a3e --- /dev/null +++ b/langs/tr/tutorials/stores_nested_reactivity/lesson.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { For, createSignal } from \"solid-js\";\n\nconst App = () => {\n const [todos, setTodos] = createSignal([])\n let input;\n let todoId = 0;\n\n const addTodo = (text) => {\n setTodos([...todos(), { id: ++todoId, text, completed: false }]);\n }\n const toggleTodo = (id) => {\n setTodos(todos().map((todo) => (\n todo.id !== id ? todo : { ...todo, completed: !todo.completed }\n )));\n }\n\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n \n
    \n \n {(todo) => {\n const { id, text } = todo;\n console.log(`Creating ${text}`)\n return
    \n \n {text}\n
    \n }}\n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_nested_reactivity/lesson.md b/langs/tr/tutorials/stores_nested_reactivity/lesson.md new file mode 100644 index 00000000..6f6fc5ec --- /dev/null +++ b/langs/tr/tutorials/stores_nested_reactivity/lesson.md @@ -0,0 +1,32 @@ +İç içe güncellemeleri bağımsız olarak işlenebilir olması, Solid'deki incelikli reaktivitenin nedenlerinden biridir. Bir kullanıcı listesine sahip olabilirsiniz, bunun içerisindeki bir ismi güncellediğimizde listenin kendisini değiştirilmeden sadece DOM'daki tek bir konum güncellenir. Bunu çok az framework (reaktif olsalar bile) başarabilmiştir. + +Peki bunu nasıl başarıyoruz? Örnekte bir sinyal içerisinde todo listemiz var. Bir todo'yu tamamlandı olarak işaretlemek için, todo bir klon ile değiştirilmelidir. Çoğu framework bu şekilde çalışır, ancak listeyi farklılaştırarak yeniden çalıştırdığımız ve bunun sonucunda - `console.log` ile gösterildiği gibi - DOM elemanları yeniden oluşturulduğu için bu gereksiz bir yük oluşturur. + +```js +const toggleTodo = (id) => { + setTodos( + todos().map((todo) => (todo.id !== id ? todo : { ...todo, completed: !todo.completed })), + ); +}; +``` + +Bunun yerine, Solid ile biz veriyi iç içe geçmiş sinyaller ile oluşturabiliriz: + +```js +const addTodo = (text) => { + const [completed, setCompleted] = createSignal(false); + setTodos([...todos(), { id: ++todoId, text, completed, setCompleted }]); +}; +``` + +Artık `setCompleted` fonksiyonunu çağırarak herhangi bir ek farklılaştırma oluşturmadan state'i güncelleyebiliriz. Bunun nedeni, karmaşıklığı view'dan alıp veriye taşımış olmamızdır ve verinin nasıl değiştiğini tam olarak bilmekteyiz. + +```js +const toggleTodo = (id) => { + const todo = todos().find((t) => t.id === id); + if (todo) todo.setCompleted(!todo.completed()) +} +``` +Kalan `todo.completed` referanslarını `todo.completed()` ile değiştirirseniz, örnek artık bir todo'yu değiştirdiğinizde değil, yalnızca oluşturduğunuzda `console.log`'u çalıştırmaktadır. + +Bu elbette bazı manuel eşlemeler gerektir ve geçmişte bizim için mevcut olan tek seçenekti. Ancak artık, proxy'ler ile bu işin çoğunu manuel müdahale olmaksızın arka planda yapabiliriz. Nasıl yapıldığını görmek için sonraki eğitimlerle devam edin. diff --git a/langs/tr/tutorials/stores_nested_reactivity/solved.json b/langs/tr/tutorials/stores_nested_reactivity/solved.json new file mode 100644 index 00000000..40223ce6 --- /dev/null +++ b/langs/tr/tutorials/stores_nested_reactivity/solved.json @@ -0,0 +1,8 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport { For, createSignal } from \"solid-js\";\n\nconst App = () => {\n const [todos, setTodos] = createSignal([])\n let input;\n let todoId = 0;\n\n const addTodo = (text) => {\n const [completed, setCompleted] = createSignal(false); \n setTodos([...todos(), { id: ++todoId, text, completed, setCompleted }]);\n }\n const toggleTodo = (id) => {\n const todo = todos().find((t) => t.id === id);\n if (todo) todo.setCompleted(!todo.completed())\n }\n\n return (\n <>\n
    \n \n {\n if (!input.value.trim()) return;\n addTodo(input.value);\n input.value = \"\";\n }}\n >\n Add Todo\n \n
    \n \n {(todo) => {\n const { id, text } = todo;\n console.log(`Creating ${text}`)\n return
    \n \n {text}\n
    \n }}\n
    \n \n );\n};\n\nrender(App, document.getElementById(\"app\"));\n" + } + ] +} diff --git a/langs/tr/tutorials/stores_nocontext/lesson.json b/langs/tr/tutorials/stores_nocontext/lesson.json new file mode 100644 index 00000000..eee66efc --- /dev/null +++ b/langs/tr/tutorials/stores_nocontext/lesson.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport counter from \"./counter\"\n\nfunction Counter() {\n return (\n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "counter", + "content": "import { createSignal, createMemo, createRoot } from \"solid-js\";\n\nfunction createCounter() {\n const [count, setCount] = createSignal(0);\n const increment = () => setCount(count() + 1);\n const doubleCount = createMemo(() => count() * 2);\n return { count, doubleCount, increment };\n}\n\nexport default createRoot(createCounter);" + } + ] +} diff --git a/langs/tr/tutorials/stores_nocontext/lesson.md b/langs/tr/tutorials/stores_nocontext/lesson.md new file mode 100644 index 00000000..f85fc34e --- /dev/null +++ b/langs/tr/tutorials/stores_nocontext/lesson.md @@ -0,0 +1,31 @@ +Context, store'lar için harika bir araçtır. Injection'u yönetir, ownership'i reaktif grafiğe bağlar, otomatik olarak disposal'ları yönetir ve tüm bunları yaparken render için ek yük oluşturmaz. + +Yine de bazen context kullanmak aşırıya kaçabilir, alternatifi reaktif sistemi doğrudan kullanmaktır. Örneğin, global kapsamda bir sinyal oluşturarak bunu diğer modüllerin kullanması için `export` edip bir reaktif data store oluşturabiliriz. + +```js +import { createSignal } from 'solid-js'; + +export default createSignal(0); + +// kullanmak istediğimiz başka bir yer: +import counter from './counter'; +const [count, setCount] = counter; +``` + +Solid'in reaktivitesi evrensel bir kavramdır, bileşenlerin içinde ya da dışında olması fark etmez. Global veya local state'için ayrı bir konsept yoktur ve hepsi birbirine denktir. + +Tek kısıtlama, tüm hesaplamaların (Efektler/Memolar) reaktif bir kök (`createRoot`) altında oluşturulması gereksinimidir. Solid'in render'ı bunu otomatik yapmaktadır. + +Bu örnekte `counter.tsx` global bir store'dur. `main.tsx` içinde, bileşenimizi şu şekilde düzenleyerek kullanabiliriz: + +```jsx +const { count, doubleCount, increment } = counter; + +return ( + +); +``` + +Sonuç olarak, hesaplamalar içeren karmaşık bir global store oluşturacağınız zaman bir root oluşturduğunuza dikkat edin. Ya da daha iyisi kendinize bir iyilik yapın ve sadece context kullanın. diff --git a/langs/tr/tutorials/stores_nocontext/solved.json b/langs/tr/tutorials/stores_nocontext/solved.json new file mode 100644 index 00000000..956fda6b --- /dev/null +++ b/langs/tr/tutorials/stores_nocontext/solved.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "name": "main", + "content": "import { render } from \"solid-js/web\";\nimport counter from \"./counter\"\n\nfunction Counter() {\n const { count, doubleCount, increment } = counter;\n\n return (\n \n );\n}\n\nrender(() => , document.getElementById(\"app\"));\n" + }, + { + "name": "counter", + "content": "import { createSignal, createMemo, createRoot } from \"solid-js\";\n\nfunction createCounter() {\n const [count, setCount] = createSignal(0);\n const increment = () => setCount(count() + 1);\n const doubleCount = createMemo(() => count() * 2);\n return { count, doubleCount, increment };\n}\n\nexport default createRoot(createCounter);" + } + ] +}