
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A form component. inspiration
npm install rhform --save
# or
yarn add rhform
const store = new FormStore({ name: 'test' })
store.reset()
function assert(condition, message) {
if (!condition) throw new Error(message)
}
const rules = {
name: (val) => assert(!!val && !!val.trim(), 'Name is required'),
}
const store = new FormStore({}, rules)
// ...
try {
const values = await store.validate()
console.log('values:', values)
} catch (error) {
console.log('error:', error)
}
function App() {
const [store] = useFormStore(
{
username: 'Default',
password: '',
gender: 'male',
contact: {
phone: '1n2,mk8798y23,cLKJlk1',
address: 'sdsdsd1',
checkbox: [],
radio: '',
},
},
{
username: {
fn(v) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (v === 'as') {
reject('error这是一个错误')
}
//promise 验证方法, 必须明确结果, 不然验证会超时
resolve()
}, 1000)
})
},
},
radio: {
fn(v) {
if (v === 'radio1') {
return '错误'
}
},
},
}
)
// console.log(store, '===+++==')
const onReset = React.useCallback((e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
console.log(JSON.stringify(store), 'reseted')
}, [])
const onSubmit = React.useCallback(async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
console.log(JSON.stringify(store), 'submit')
}, [])
return (
<Form
as='form'
store={store}
onSubmit={onSubmit}
onReset={onReset}
inline={boolean('Inline', false)}
labelWidth={number('Label Width', 120)}
labelAlign={select('labelAlign', ['left', 'right', 'center'], 'left')}
gutter={number('Gutter', 20)}
>
<Form.Item
required={boolean('RequiredName', true)}
error={store.error('username')}
label='username'
>
<Form.Field type='text' name='username' rule={{ fn: 'required' }} loadingAs='loading...' />
{store.get('username')}
</Form.Item>
<Form.Item
required={boolean('RequiredRadioCheckbox', false)}
label='radio checkbox'
error={store.error('radio')}
>
<div>
<Form.Field type='radio' name='radio' value='radio1' />
<Form.Field type='radio' name='radio' value='radio2' />
{store.get('radio')}
</div>
<Form.Field type='checkbox' name='checkbox' value='checkbox1' />
<Form.Field type='checkbox' name='checkbox' value='checkbox2' />
<Form.Field type='checkbox' name='checkbox' value='checkbox3' />
{(Array.isArray(store.get('checkbox'))
? store.get('checkbox')
: [store.get('checkbox')]
).map((i) => {
return i
})}
</Form.Item>
<Form.Item label='Gender' error={store.error('contact.phone')}>
<Form.Field as='select' multiple name='select'>
<option value='male'>Male</option>
<option value='female'>Female</option>
<option value='1d'>1d</option>
<option value='czxc'>czxc</option>
<option value='13f'>13f</option>
</Form.Field>
{(store.get('select') || []).map((i) => {
return i
})}
<Form.Field as='select' name='select2'>
<option value='male'>Male</option>
<option value='female'>Female</option>
<option value='1d'>1d</option>
<option value='czxc'>czxc</option>
<option value='13f'>13f</option>
</Form.Field>
{store.get('select2')}
<select>
<option value='male'>Male</option>
<option value='female'>Female</option>
<option value='1d'>1d</option>
<option value='czxc'>czxc</option>
<option value='13f'>13f</option>
</select>
</Form.Item>
<Form.Item label='Phone'>
<Form.Field name='Phone' type='text' />
{store.get('Phone')}
</Form.Item>
<Form.Item label='Address'>
<Form.Field name='Address' type='text' />
{store.get('Address')}
</Form.Item>
<Form.Item label=''>
<button
type='button'
onClick={() => {
console.log('===button click==')
}}
>
Button
</button>
<button type='submit'>Submit</button>
<button type='reset'>Reset</button>
</Form.Item>
</Form>
)
}
class App extends React.Component {
state: {
aaa: string,
store: any,
}
store: FormStoreInstance
constructor(props) {
super(props)
this.state = {
aaa: '',
store: {
checkbox: 'checkbox1',
username: 'Default',
password: '',
gender: 'male',
contact: {
phone: '',
address: 'sdsdsd1',
checkbox: [],
radio: '',
},
},
}
this.store = new FormStore(
this.state.store,
(value) => {
this.setState({
store: value,
})
},
{
username: {
fn(v) {
// if (v === 'as') {
// return 'error这是一个错误'
// }
// return true
return new Promise((resolve, reject) => {
setTimeout(() => {
if (v === 'as') {
reject('error这是一个错误')
}
//promise 验证方法, 必须明确结果, 不然验证会超时
resolve()
}, 1000)
})
},
},
}
)
}
onReset = (e) => {
console.log(JSON.stringify(this.store), 'reseted')
}
onSubmit = async (e) => {
console.log(JSON.stringify(this.store), 'submited')
}
render() {
// console.log(this.store, '======')
const store = this.store
const onSubmit = this.onSubmit.bind(this)
const onReset = this.onReset.bind(this)
return (
<Form
as='form'
store={store}
onSubmit={onSubmit}
onReset={onReset}
inline={boolean('Inline', false)}
labelWidth={number('Label Width', 120)}
labelAlign={select('labelAlign', ['left', 'right', 'center'], 'left')}
gutter={number('Gutter', 20)}
>
<Form.Item
required={boolean('RequiredName', true)}
error={store.error('username')}
label='username'
>
<Form.Field
type='text'
name='username'
rule={{ fn: 'required' }}
loadingAs='loading...'
/>
{store.get('username')}
</Form.Item>
<Form.Item
required={boolean('RequiredRadioCheckbox', false)}
label='radio checkbox'
error={store.error('radio')}
>
<div>
<Form.Field type='radio' name='radio' value='radio1' />
<Form.Field type='radio' name='radio' value='radio2' />
{store.get('radio')}
</div>
<Form.Field type='checkbox' name='checkbox' value='checkbox1' />
<Form.Field type='checkbox' name='checkbox' value='checkbox2' />
<Form.Field type='checkbox' name='checkbox' value='checkbox3' />
{(Array.isArray(store.get('checkbox'))
? store.get('checkbox')
: [store.get('checkbox')]
).map((i) => {
return i
})}
</Form.Item>
<Form.Item label='Gender' error={store.error('contact.phone')}>
<Form.Field as='select' multiple name='select'>
<option value='male'>Male</option>
<option value='female'>Female</option>
<option value='1d'>1d</option>
<option value='czxc'>czxc</option>
<option value='13f'>13f</option>
</Form.Field>
{(store.get('select') || []).map((i) => {
return i
})}
<Form.Field as='select' name='select2'>
<option value='male'>Male</option>
<option value='female'>Female</option>
<option value='1d'>1d</option>
<option value='czxc'>czxc</option>
<option value='13f'>13f</option>
</Form.Field>
{store.get('select2')}
<select>
<option value='male'>Male</option>
<option value='female'>Female</option>
<option value='1d'>1d</option>
<option value='czxc'>czxc</option>
<option value='13f'>13f</option>
</select>
</Form.Item>
<Form.Item label='Phone'>
<Form.Field name='Phone' type='text' />
{store.get('Phone')}
</Form.Item>
<Form.Item label='Address'>
<Form.Field name='Address' type='text' />
{store.get('Address')}
</Form.Item>
<Form.Item label=''>
<button
type='button'
onClick={() => {
console.log('===button click==')
}}
>
Button
</button>
<button type='submit'>Submit</button>
<button type='reset'>Reset</button>
</Form.Item>
</Form>
)
}
}
<Form>props
| name | type | default | description | required |
|---|---|---|---|---|
| className | string | '' | class name | false |
| children | React.ReactNode | '' | children | false |
| store | FormStoreInstance | '' | store instance | true |
| as | React.ComponentType<any>;string;React.ComponentType;React.ForwardRefExoticComponent<any> | 'form' | native element | false |
events
| name | type | default | description | required |
|---|---|---|---|---|
| onSubmit | (e: React.FormEvent) => void | '' | submit | false |
| onReset | (e: React.FormEvent) => void | '' | reset | false |
<FormItem>props
| name | type | default | description | required |
|---|---|---|---|---|
| className | string | '' | class name | false |
| children | React.ReactNode | '' | children | false |
| label | string | '' | label | false |
| name | string | '' | name | false |
| required | boolean | '' | required | false |
| labelWidth | number | '' | label width | false |
| labelAlign | Property.TextAlign | '' | label align | false |
| error | any | '' | error | false |
| suffix | React.ReactNode | '' | error | false |
<FormField>props
| name | type | default | description | required |
|---|---|---|---|---|
| as | 'input';'select';'textarea';FunctionComponent<P>;ComponentClass<P>;string | 'input' | native element | false |
| children | React.ReactNode | '' | children | false |
| name | string | '' | name | true |
| valueKey | string | '' | valueKey | false |
| valueGetter | ValueGetter | '' | ValueGetter | false |
| loadingAs | FunctionComponent<any> ; ComponentClass<any> ; string | '' | loading native element | false |
| type | string | '' | type | false |
| value | any | '' | value | false |
| multiple | boolean | '' | multiple | false |
| rule | Rule ; Rule[] | '' | rule | false |
| validateTrigger | 'onChange' ; 'onBlur' ; string | 'onChange' | validateTrigger | false |
| validateTrigger | 'onChange' ; 'onBlur' ; string | 'onChange' | validateTrigger | false |
interface FormStoreConstructor<T extends Object = any> {
new (
store: T,
changed: React.Dispatch<React.SetStateAction<Partial<T>>>,
rules?: Rules
): FormStoreInstance<T>
validator: Record<string, ValidatorFn>
}
interface FormStoreInstance<T extends Object = any> {
store: T
changed: React.Dispatch<React.SetStateAction<Partial<T>>>
rules: Rules
initialValues: T
names: Record<string, number>
errors: Record<string, ValidResult>
validStacks: Record<string, (Promise<ValidResult> | ValidResult)[]>
validLoadings: Record<string, boolean>
addName(name: string): void
removeName(name: string): void
addRule(name: string, newRule: Rule): void
removeRule(name: string, newRule: Rule): void
initStore(v: T): T
reset(): void
has(name: string): boolean
get(name?: string): any | undefined
unset(name: string): void
set<V>(name: string, v?: V, refresh?: boolean): void
refresh(): void
setLoading(name: string): void
unsetLoading(name: string): void
isLoading(name: string): boolean
validate: DebouncedFunc<
(
name?: string | undefined,
silent?: boolean | undefined
) => Promise<ValidResult>
>
setError(name: string, msg: string): void
unsetError(name: string): void
error(name: string): ValidResult
}
FAQs
React component Form
We found that rhform demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.