# Custom Serializers
## Use cases
Third party CustomClass implements something important and requires methods to work with the data.
## Simplest possible usage
### PROBLEM
```typescript
export default component$(() => {
const url = new URL(); // works!
const value = new CustomClass(3434); // breaks serialization
return (
<div onClick$={() => {
console.log(url);
console.log(value.method());
}} />
)
});
```
### CURRENT SOLUTION 0 (userspace)
- :-1: state must be stored separate from CustomClass
- :-1: user must know shape of state to call methods
- :-1: state must be updated on every change
- :-1: CustomClass must be checked + inited in every callback
```typescript
import CustomClass from 'customClass'
// USER PROVIDES THIS
export const ensureClass = (theClass, obj) => {
if (!obj.v)
obj.v = noSerialize(new theClass(
obj.state,
// needs runtime serialization instead of once at pause time
{updatePlainState: s=>obj.state=s}
))
return obj
}
export default component$(() => {
const url = new URL(); // works!
// AWKWARD initialization
const value = ensureClass(CustomClass, {
state: 3434,
})
return (
<div onClick$={
async () => {
const [url, value] = await useLexicalScope();
// NEEDED IN ALL CALLBACKS
ensureClass(CustomClass, value)
console.log(url);
console.log(value.v.method());
}} />
)
});
```
### SOLUTION 1 (changes useLexicalScope)
- :+1: state is exactly what is expected
- :+1: state is just the object
- :+1: state gets serialized only when needed
- :+1: CustomClass gets inited only on scope resume
- customSerializer$ tags object with parse+stringify
- when pausing, customSerializer-serializer stores QRL of both + stringified value
- when resuming, useLexicalScope imports parser and parses value
- useLexicalScope is async only on qwikloader calls
- never from runtime calls
- runtime call can preserialize everything
- stringifier is needed on pause so either pause is async or needs pre-import
- changes useLexicalScope
- optimizer needs to write call differently
- runtime needs to check scope for QRLs to load before calling handler
```typescript!
import CustomClass from 'customClass'
export default component$(() => {
const url = new URL(); // works!
// CustomClass defines .parse and .stringify
const value = customSerializerQrl($(CustomClass), new CustomClass(3434));
return (
<div onClick$={
() => useLexicalScope((url, value) => {
console.log(url);
console.log(value.method());
})} />
)
});
```
### SOLUTION 2 (pure runtime)
```typescript
import CustomClass from 'customClass'
export default component$(() => {
const url = new URL(); // works!
const value: CustomSerialze<CustomClass> = customSerializerQrl($(CustomClass), new CustomClass(3434));
return (
<div onClick$={
async () => {
const [url, value] = useLexicalScope();
console.log(url);
const a = await value.resolve(); // added friction
console.log(a.method());
}} />
)
});
```
### SOLUTION 3 (async)
This breaks everything :)
```typescript
import CustomClass from 'customClass'
export default component$(() => {
const url = new URL(); // works!
const value: CustomSerialze<CustomClass> = customSerializerQrl($(CustomClass), new CustomClass(3434));
return (
<div onClick$={
async () => {
const [url, value] = await useLexicalScope();
console.log(url);
console.log(value.method());
}} />
)
});
```
## how qwikloader works when handler clicked
```json
// could await import all parsers
const mod = await import('path.js');
// could await import all parsers for this handler's scope
const handler = mod['symbol'];
globalContext = [element];
// could await parsers in handler
// BUT must read context first
handler();
globalContext = undefined;
```