Skip to content

Commit 069f973

Browse files
WIP.
1 parent b79f850 commit 069f973

File tree

5 files changed

+73
-83
lines changed

5 files changed

+73
-83
lines changed

src/app.tsx

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useForceUpdate } from "./force-update";
77

88
import "./reset.scss";
99
import "./app.scss";
10+
import { Test1 } from "./tests/test1";
1011

1112
const store = new GroupStoreMutable();
1213
const Test = () => {
@@ -26,30 +27,11 @@ const Test = () => {
2627
groupId: "person"
2728
};
2829

29-
const [show, setShow] = useState(true);
30-
3130
return (
3231
<>
3332
<div className="forms">
3433
<GroupContext.Provider value={groupContext}>
35-
<div>
36-
<button onClick={() => setShow(!show)}>
37-
{!show ? "Mount" : "Unmount"}
38-
</button>
39-
<label>
40-
Last name
41-
{show ? (
42-
<TextField
43-
name="lastName"
44-
initialValue="Smith"
45-
/>
46-
) : null}
47-
</label>
48-
<label>
49-
First name
50-
<TextField name="firstName" initialValue="John" />
51-
</label>
52-
</div>
34+
<Test1 />
5335
</GroupContext.Provider>
5436
</div>
5537
<div className="store">
@@ -69,7 +51,7 @@ const Test = () => {
6951
</pre>
7052
</div>
7153
<div className="store-result">
72-
{JSON.stringify(store.toObject())}
54+
{JSON.stringify(store.toObject(), null, 4)}
7355
</div>
7456
</>
7557
);

src/components/group-field.tsx

Whitespace-only changes.

src/components/text-field.tsx

Lines changed: 35 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useContext, useEffect, useState } from "react";
22
import { FieldContext } from "../contexts/field-context";
33
import { GroupContext } from "../contexts/group-context";
44
import { useForceUpdate } from "../force-update";
5+
import { GroupStore } from "../stores/group-store";
56

67
export interface FieldValues {
78
defaultValue?: string;
@@ -13,55 +14,31 @@ export interface TextFieldProps extends FieldValues {
1314
name: string;
1415
}
1516

16-
export const SEPARATOR = ".";
17-
18-
function useFieldId(props: Pick<TextFieldProps, "name">): string {
19-
const { groupId } = useContext(GroupContext);
20-
if (groupId == null) {
21-
return props.name;
22-
}
23-
return `${groupId}${SEPARATOR}${props.name}`;
17+
interface FieldResult {
18+
store: GroupStore;
19+
fieldId: string;
20+
fieldProps: JSX.IntrinsicElements["input"];
2421
}
2522

26-
function useRegisterField(
27-
fieldId: string,
28-
props: TextFieldProps,
29-
updateHandler: () => void
30-
): void {
31-
useEffect(() => {
32-
const { store } = useContext(GroupContext);
23+
function useField(props: TextFieldProps): FieldResult {
24+
const [currentValue, setCurrentValue] = useState("");
3325

34-
let { defaultValue, initialValue } = props;
35-
if (defaultValue == null) {
36-
defaultValue = "";
37-
}
26+
const { store, groupId } = useContext(GroupContext);
3827

39-
if (initialValue == null) {
40-
initialValue = defaultValue;
41-
}
28+
if (groupId == null) {
29+
// TODO: Error message.
30+
throw new Error("groupId is not defined.");
31+
}
4232

43-
store.registerField(fieldId, props.name, defaultValue, initialValue);
33+
let { defaultValue, initialValue } = props;
4434

45-
store.addListener(updateHandler);
35+
const fieldId = store.generateFieldId(props.name, groupId);
4636

47-
return () => {
48-
// First, remove listener to not get any more updates.
49-
store.removeListener(updateHandler);
50-
// Then, unregister field.
51-
store.unregisterField(fieldId);
52-
};
53-
}, []);
54-
}
55-
56-
export const TextField = (props: TextFieldProps) => {
57-
const { store } = useContext(GroupContext);
58-
const [currentValue, setCurrentValue] = useState("");
59-
60-
const fieldId = useFieldId(props);
37+
const onChange: React.ChangeEventHandler<HTMLInputElement> = event => {
38+
store.updateValue(fieldId, event.target.value);
39+
};
6140

6241
useEffect(() => {
63-
let { defaultValue, initialValue } = props;
64-
6542
if (defaultValue == null) {
6643
defaultValue = "";
6744
}
@@ -70,40 +47,38 @@ export const TextField = (props: TextFieldProps) => {
7047
initialValue = defaultValue;
7148
}
7249

73-
store.registerField(fieldId, props.name, defaultValue, initialValue);
50+
store.registerField(props.name, groupId, defaultValue, initialValue);
7451

75-
const updateValue = () => {
52+
const storeUpdated = () => {
7653
const field = store.getField(fieldId);
7754
if (field == null) {
7855
return;
7956
}
8057
setCurrentValue(field.currentValue);
8158
};
82-
updateValue();
59+
storeUpdated();
8360

84-
store.addListener(updateValue);
61+
store.addListener(storeUpdated);
8562

8663
return () => {
87-
store.removeListener(updateValue);
64+
// First, remove listener to not get any more updates.
65+
store.removeListener(storeUpdated);
66+
// Then, unregister field.
8867
store.unregisterField(fieldId);
8968
};
9069
}, []);
91-
92-
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
93-
const value = event.target.value;
94-
store.updateValue(fieldId, value);
70+
return {
71+
fieldId: fieldId,
72+
store: store,
73+
fieldProps: {
74+
value: currentValue,
75+
onChange: onChange
76+
}
9577
};
78+
}
9679

97-
const onFocus = (event: React.FocusEvent<HTMLInputElement>) => {
98-
console.debug(event.target);
99-
};
80+
export const TextField = (props: TextFieldProps) => {
81+
const { fieldId, store, fieldProps } = useField(props);
10082

101-
return (
102-
<input
103-
type="text"
104-
value={currentValue}
105-
onChange={onChange}
106-
onFocus={onFocus}
107-
/>
108-
);
83+
return <input type="text" {...fieldProps} />;
10984
};

src/stores/group-store.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TinyEmitter, Callback } from "../helpers/emitter";
22
import produce from "immer";
3-
import { runInThisContext } from "vm";
3+
4+
export const SEPARATOR = ".";
45

56
interface Field {
67
id: string;
@@ -25,12 +26,18 @@ export class GroupStoreMutable extends TinyEmitter<Callback> {
2526
return this.fields[fieldId];
2627
}
2728

29+
public generateFieldId(name: string, groupId: string): string {
30+
return `${groupId}${SEPARATOR}${name}`;
31+
}
32+
2833
public registerField(
29-
id: string,
3034
name: string,
35+
groupId: string,
3136
defaultValue: string,
3237
initialValue: string
3338
): void {
39+
const id = this.generateFieldId(name, groupId);
40+
3441
if (this.fields[id] != null) {
3542
throw new Error(`Field with an id '${id}' is already registered.`);
3643
}
@@ -47,6 +54,7 @@ export class GroupStoreMutable extends TinyEmitter<Callback> {
4754
fields[id] = newField;
4855
});
4956
this.emit();
57+
return id;
5058
}
5159

5260
public unregisterField(id: string): void {

src/tests/test1.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React, { useState } from "react";
2+
import { TextField } from "../components/text-field";
3+
4+
export const Test1 = () => {
5+
const [show, setShow] = useState(true);
6+
return (
7+
<>
8+
<div>
9+
<button onClick={() => setShow(!show)}>
10+
{!show ? "Mount" : "Unmount"}
11+
</button>
12+
<label>
13+
First name
14+
<TextField name="firstName" initialValue="John" />
15+
</label>
16+
<label>
17+
Last name
18+
{show ? (
19+
<TextField name="lastName" initialValue="Smith" />
20+
) : null}
21+
</label>
22+
</div>
23+
</>
24+
);
25+
};

0 commit comments

Comments
 (0)