EN
React - form submit button in root component
2 answers
3 points
How do I implement submit button on the root component which has several child components that has a part of a form?
xxxxxxxxxx
1
function Root(props) {
2
return (
3
<>
4
<div>
5
<Component1 />
6
<Component2 />
7
<Component3 />
8
<Component4 />
9
<div>
10
<button className="button" type="submit">
11
submit
12
</button>
13
</div>
14
</div>
15
</>
16
);
17
};
18
19
ReactDom.render(<Root/>, div);
2 answers
4 points
In this article you should find the solution.
Finally you can use it this way:
xxxxxxxxxx
1
// Note: Uncomment import lines during working with JSX Compiler.
2
// import React from 'react';
3
// import ReactDOM from 'react-dom';
4
5
const getProperty = (object, path) => {
6
if (object == null) { // undefined or null
7
return object;
8
}
9
const parts = path.split('.');
10
for (let i = 0; i < parts.length; ++i) {
11
if (object == null) { // undefined or null
12
return undefined;
13
}
14
const key = parts[i];
15
object = object[key];
16
}
17
return object;
18
};
19
20
const setProperty = (object, path, value) => {
21
const parts = path.split('.');
22
const limit = parts.length - 1;
23
for (let i = 0; i < limit; ++i) {
24
const key = parts[i];
25
object = object[key] ?? (object[key] = {});
26
}
27
const key = parts[limit];
28
object[key] = value;
29
};
30
31
const iterateElements = (form, callback) => {
32
const elements = form.elements;
33
for (let i = 0; i < elements.length; ++i) {
34
const element = elements[i];
35
const tag = element.tagName;
36
if (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA') {
37
callback(element);
38
}
39
}
40
};
41
42
const getData = (form) => {
43
const data = {};
44
iterateElements(form, element => {
45
setProperty(data, element.name, element.value);
46
});
47
return data;
48
};
49
50
const bindData = (form, data) => {
51
iterateElements(form, element => {
52
const value = getProperty(data, element.name);
53
element.value = String(value ?? '');
54
});
55
};
56
57
const Form = React.forwardRef(({data, children, onSubmit}, ref) => {
58
const formRef = ref ?? React.useRef();
59
React.useEffect(() => {
60
const form = formRef.current;
61
if (form) {
62
bindData(form, data ?? {});
63
}
64
}, [data]);
65
const handleSubmit = e => {
66
e.preventDefault();
67
if (onSubmit) {
68
onSubmit(getData(formRef.current));
69
}
70
};
71
return (
72
<form ref={formRef} onSubmit={handleSubmit}>
73
{children}
74
</form>
75
);
76
});
77
78
79
// Usage example:
80
81
const areaStyle = { border: '1px solid gray' };
82
83
const UserArea = () => {
84
return (
85
<div style={areaStyle}>
86
<div>User:</div>
87
<div>
88
<label>Username: </label>
89
<input type="text" name="user.username" />
90
</div>
91
<div>
92
<label>Password: </label>
93
<input type="password" name="user.password" />
94
</div>
95
</div>
96
);
97
};
98
99
const ReportArea = () => {
100
return (
101
<div style={areaStyle}>
102
<div>Report:</div>
103
<div>
104
<label>Title: </label>
105
<input type="text" name="report.title" />
106
</div>
107
<div>
108
<label>Goal: </label>
109
<input type="text" name="report.goal" />
110
</div>
111
</div>
112
);
113
};
114
115
const App = () => {
116
const data = {
117
user: {
118
username: 'john',
119
password: 'Secret$$'
120
},
121
report: {
122
title: 'My raport title',
123
goal: 'My raport goal'
124
}
125
};
126
const handleSubmit = data => {
127
const json = JSON.stringify(data, null, 4);
128
console.clear();
129
console.log(json);
130
};
131
return (
132
<div>
133
<Form data={data} onSubmit={handleSubmit}>
134
<UserArea />
135
<ReportArea />
136
<button type="submit">Submit</button>
137
</Form>
138
</div>
139
);
140
};
141
142
const root = document.querySelector('#root');
143
ReactDOM.render(<App />, root);
Sources
2 commentsShow commentsAdd comment
2y
what if I want to handle state individually for each component. How to I go about that?
2y
You should use useState() for each field and exchange state with use context() or events in child components
1 points
The solution that stores each field in the separated state:
xxxxxxxxxx
1
// Note: Uncomment import lines during working with JSX Compiler.
2
// import React from 'react';
3
// import ReactDOM from 'react-dom';
4
5
const areaStyle = { border: '1px solid gray' };
6
7
const TextInput = ({ label, value, onChanged }) => {
8
const [localValue, setLocalValue] = React.useState(value);
9
React.useEffect(() => setLocalValue(value), [value]);
10
const handleChange = e => setLocalValue(e.target.value);
11
const handleBlur = e => onChanged?.(localValue);
12
return (
13
<label>
14
<span>{label}</span>
15
<input type="text" value={localValue} onChange={handleChange} onBlur={handleBlur} />
16
</label>
17
);
18
};
19
20
const UserArea = ({ username, password, onUsernameChanged, onPasswordChanged }) => {
21
return (
22
<div style={areaStyle}>
23
<div>User:</div>
24
<TextInput label="Username:" value={username} onChanged={onUsernameChanged} />
25
<br />
26
<TextInput label="Password:" value={password} onChanged={onPasswordChanged} />
27
</div>
28
);
29
};
30
31
const ReportArea = ({ title, goal, onTitleChanged, onGoalChanged }) => {
32
return (
33
<div style={areaStyle}>
34
<div>Report:</div>
35
<TextInput label="Title:" value={title} onChanged={onTitleChanged} />
36
<br />
37
<TextInput label="Goal:" value={goal} onChanged={onGoalChanged} />
38
</div>
39
);
40
};
41
42
const App = () => {
43
const [username, setUsername] = React.useState('');
44
const [password, setPassword] = React.useState('');
45
const [title, setTitle] = React.useState('');
46
const [goal, setGoal] = React.useState('');
47
const handleFormSubmit = e => {
48
e.preventDefault();
49
// add some logic here ...
50
};
51
const handleUsernameChanged = value => {
52
setUsername(value);
53
console.log(value);
54
};
55
const handlePasswordChanged = value => {
56
setPassword(value);
57
console.log(value);
58
};
59
const handleTitleChanged = value => {
60
setTitle(value);
61
console.log(value);
62
};
63
const handleGoalChanged = value => {
64
setGoal(value);
65
console.log(value);
66
};
67
return (
68
<div>
69
<form onSubmit={handleFormSubmit}>
70
<UserArea
71
username={username}
72
password={password}
73
onUsernameChanged={handleUsernameChanged}
74
onPasswordChanged={handlePasswordChanged}
75
/>
76
<ReportArea
77
title={title}
78
goal={goal}
79
onTitleChanged={handleTitleChanged}
80
onGoalChanged={handleGoalChanged}
81
/>
82
<button type="submit">Submit</button>
83
</form>
84
</div>
85
);
86
};
87
88
const root = document.querySelector('#root');
89
ReactDOM.render(<App />, root);
See also
0 commentsAdd comment