Reputation: 736
I'm building a an app in React/Redux and I have some input fields that lose focus after each key stroke. My code looks like this:
<General fields={props.general}
onChange={value => props.updateValue('general', value)} />
<FormWrapper>
<Network fields={props.network}
onChange={value => props.updateValue('network', value} />
</NetworkTableForm>
</FormWrapper>
General
and Network
just contain different sections of the form and FormWrapper
can wrap a subsection of the form and provide some interesting visualisations. The problem is that all of the fields in General
work fine but the fields in Network
lose focus after each keystroke. I've already tried appending keys to a bunch of different elements such as General
Network
, FormWrapper
and my components wrapping my input fields and the reason that I'm not using redux-form is because it doesn't work well with the UI framework that I'm using(Grommet). Any idea what could be causing this?
Edit: Adding more code as per request. Here's the full component:
const InfoForm = (props) => {
let FormWrapper = FormWrapperBuilder({
"configLists": props.configLists,
"showForm": props.showForm,
"loadConfiguration": props.loadConfiguration,
"updateIndex": props.updateIndex,
"metadata": props.metadata})
return (
<CustomForm onSubmit={() => console.log('test')}
loaded={props.loaded} heading={'System Details'}
header_data={props.header_data}
page_name={props.general.name} >
<General fields={props.general}
onChange={(field, value) => props.updateValue('general', field, value)} />
<FormWrapper labels={["Interface"]} fields={["interface"]} component={'network'}>
<Network fields={props.network}
onChange={(field, value) => props.updateValue('network', field, value)} />
</FormWrapper>
<User fields={props.user}
onChange={(field, value) => props.updateValue('user', field, value)} />
</CustomForm>
)
}
export default InfoForm
Here's an example of a form section component:
const Network = ({fields, onChange}) => (
<CustomFormComponent title='Network'>
<CustomTextInput value={fields.interface} label='Interface'
onChange={value => onChange('interface', value)} />
<CustomIPInput value={fields.subnet} label='Subnet'
onChange={value => onChange('subnet', value)} />
<CustomIPInput value={fields.network} label='Network'
onChange={value => onChange('network', value)} />
<CustomIPInput value={fields.gateway} label='Gateway'
onChange={value => onChange('gateway', value)} />
<CustomIPInput value={fields.nat_ip} label='NAT'
onChange={value => onChange('nat_ip', value)} />
</CustomFormComponent>
)
export default Network
Here's an example of one of the custom inputs:
const CustomTextInput = ({label, value, onChange}) => (
<FormField label={<Label size='small'>{label}</Label>}>
<Box pad={{'horizontal': 'medium'}}>
<TextInput placeholder='Please Enter' value={value}
onDOMChange={event => onChange(event.target.value)}
/>
</Box>
</FormField>
)
export default CustomTextInput
And here's the FormWrapperBuilder function:
const FormWrapperBuilder = (props) =>
({component, labels, fields, children=undefined}) =>
<VisualForm
configLists={props.configLists[component]}
showForm={visible => props.showForm(component, visible)}
loadConfiguration={index => props.loadConfiguration(component, index)}
updateIndex={index => props.updateIndex(component, index)}
metadata={props.metadata[component]}
labels={labels} fields={fields} >
{children}
</VisualForm>
export default FormWrapperBuilder
All of these are kept in separate files which may affect the rerendering of the page and it's the functions that are wrapped in the FormWrapper that lose focues after a state change. Also I've tried adding keys to each of these components without any luck. Also here's the functions in my container component:
const mapDispatchToProps = (dispatch) => {
return {
'updateValue': (component, field, value) => {
dispatch(updateValue(component, field, value))},
'showForm': (component, visible) => {
dispatch(showForm(component, visible))
},
'loadConfiguration': (component, index) => {
dispatch(loadConfiguration(component, index))
},
'pushConfiguration': (component) => {
dispatch(pushConfiguration(component))
},
'updateIndex': (component, index) => {
dispatch(updateIndex(component, index))
}
}
}
Edit 2: Modified my custom text input as such as per Hadas' answer. Also slathered it with keys and refs for good measure
export default class CustomTextInput extends React.Component {
constructor(props) {
super(props)
this.state = {value: ""}
}
render() {
return (
<FormField key={this.props.label} ref={this.props.label} label={<Label size='small'>{this.props.label}</Label>}>
<Box key={this.props.label} ref={this.props.label} pad={{'horizontal': 'medium'}}>
<TextInput placeholder='Please Enter' value={this.state.value} key={this.props.label} ref={this.props.label}
onDOMChange={event => { this.props.onChange(event.target.value); this.state.value = event.target.value }} />
</Box>
</FormField>
)
}
}
Upvotes: 0
Views: 3561
Reputation: 761
React is re-rendering the DOM on each key stroke. Try setting value to a variable attached to the component's state like this:
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}></TextInput
Upvotes: 1