How to prevent component from updating, if checkbox is checked - javascript

A client wants to have a numeric slider component that lets him select a number, and a checkbox that says 'no value'. When the checkbox is checked, the slider should be disabled but should still retain its previously selected configuration.
I'm having trouble implementing this using the idiomatic React way, of Components that have props and state.
I'm envisioning the two as part of a single component, a slider-checkbox, with props like this:
value : number
onChange : (newValue : number) => void
Now, if the no value checkbox is checked, then value is undefined. The problem is that because value also sets the position of the slider, this means the position will be changed once the checkbox is ticked -- and I don't want that to happen.
The problem is while React wants to keep all the components in sync, in this case we don't want to keep the slider in sync with the rest of the application. Even though the value should be undefined (or null), we still want the slider to be sitting on the last value the user picked.
What is the correct way to resolve this issue?

I don't know how your application logic works, since you haven't shared it, however you could use shouldComponentUpdate() to resolve this issue.
If shouldComponentUpdate returns false, then render() will be completely skipped until the next state change. In addition, componentWillUpdate and componentDidUpdate will not be called.
So you could do:
shouldComponentUpdate(nextProps) {
if(typeof nextProps.value === 'undefined') return false; //return false if value is undefined
return true; //otherwise always return true (this is default)
}
This will prevent the component from re-rendering if value is undefined. Though I would suggest sending in null instead, since the variable is actually defined, but has simply no value.
Note that this will not disable the slider as you requested - it will simply maintain the original render-state of the slider.
If you also want to disable the slider when the checkbox is checked, you have a couple of options here as I see it. Here's one:
Split the component into 2 sub-components
The idea here is that the props control the slider and checkbox directly, without the use of a state. This is great if you want to use Stateless Functional Components, check out my guide on how and why to use that.
Demo
So your code would be something like:
CheckboxSlider:
class CheckboxSlider extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
value: 50, //default is in the middle, 50%
disabled: false
};
}
_toggleSlider = () => {
this.setState({disabled: !this.state.disabled});
}
render() {
<div>
<Slider value={this.state.value} disabled={this.state.disabled} />
<CheckBox onCheckboxChange={this._toggleSlider} />
</div>
}
}
export default CheckboxSlider;
Slider:
import React from 'react';
const Slider = (props) => (
<input id="slider" type="range" min="0" max="100" disabled={props.disabled} />
);
export default Slider;
Checkbox:
import React from 'react';
const Checkbox = (props) => (
<input id="checkbox" type="checkbox" onChange={props.onCheckboxChange} />
);
export default Checkbox;

Use separate state to have value of slider input, to enable/disable the slider and to check/uncheck the checkbox. Below is a sample snippet.
class Slider extends React.Component {
constructor(props) {
super(props)
this.state = {
sliderValue: 100,
checkedValue: false,
enable: false
}
}
handleChange= (e) => {
this.setState({sliderValue: e.target.value});
}
handleClick = (e) => {
if(this.state.checkedValue == false) {
this.setState({checkedValue: true, enable: true}, function() {
this.refs.slider.disabled = true;
}.bind(this));
} else if(this.state.checkedValue == true) {
this.setState({checkedValue: false, enable: false});
}
}
render() {
return (
<div>
<input type="range" ref="slider" value={this.state.sliderValue} onChange={this.handleChange} min="100" max="500" step="10" disabled={this.state.enable}/>
<input type="checkbox" onChange={this.handleClick} />
</div>
)
}
}
ReactDOM.render(<Slider />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Related

update parent's state fom child component using onChange

I am trying to update the number of event from the parent component by using an input form from the child component, but there is something I am not seeing it either doesn't work or shows undefined
class App extends Component {
state = {
numberOfEvents: 32,
};
.....
updateNumberOfEvents = (eventNumber) => {
this.setState({ numberOfEvents: eventNumber });
};
render() {
return (
<div className="App">
<NumberOfEvents updateNumberOfEvents={this.updateNumberOfEvents} />
}
</div>
class NumberOfEvents extends Component {
state = {
numberOfEvents: 32,
};
handleInputChanged = (event) => {
const value = event.target.value;
this.setState({
numberOfEvents: value,
});
this.props.updateNumberOfEvents(value);
};
render() {
const numberOfEvents = this.state.numberOfEvents;
return (
<div className="numberOfEvents">
<form>
<label for="fname"> Number of Events:</label>
<input
type="text"
className="EventsNumber"
value={numberOfEvents}
onChange={this.handleInputChanged}
/>
</form>
</div>
);
}
}
export default NumberOfEvents;
this.setState({
numberOfEvents: value,
}, () => {
this.props.updateNumberOfEvents(value);
}
);
The details are here.
While this answer does make it work and correctly highlights that setState calls are asynchronous, I would suggest removing the local state inside NumberOfEvents entirely, as you currently have multiple sources of truth for your form.
Update your onChange handler:
handleInputChanged = (event) => {
this.props.updateNumberOfEvents(event.target.value);
};
and pass down the value from the parent:
<NumberOfEvents
updateNumberOfEvents={this.updateNumberOfEvents}
numberOfEvents={this.state.numberOfEvents}
/>
and use that value inside your child component:
<input
type="text"
className="EventsNumber"
value={this.props.numberOfEvents}
onChange={this.handleInputChanged}
/>
Having one source of truth is less error prone and easier to maintain, as illustrated by your current bug.
I agree with hotpink but i tried your code on codesandbox...it does not show the value undfined. Here is the link https://codesandbox.io/s/stackoverflow-iow19?file=/src/App.js.
Check console

How can I setState() another input value with a button in the same component in React?

How can I setState() another input value with a button in the same component in React?
I'm using the onClick event handler on the button.
I want to make the handleClickfunction which I gave it to the button, to target the value of the input
class Search extends Component {
state = {
searchInput: "",
};
handleClick = () => {
this.setState({
searchInput: input.value,
});
};
render() {
return (
<div>
<input type="text"/>
<button onClick={this.handleClick}>Enter</button>
</div>
);
}
}
Your question is not clear, I believe you are asking how to set the value of an input field when you press a button in react.
If that is correct, then you have done most of the work already, all you need to do now is add an <input> tag.
Like this:
<input type="text" value={ this.state.searchInput } />
If I have misunderstood your question then please clarify.
It may be worth reading about how State and Lifecycle work in React Here
Whenever the setState() function is triggered, React automatically runs the render() function in any components where state has changed, rerendering that component with the new state values.
Edit
After clarification I now understand exactly what you want.
You require the use of a ref, like this:
class Search extends Component {
state = {
searchInput: "",
};
handleClick = () => {
this.setState({
searchInput: this.inputText,
});
};
render() {
return (
<div>
<input type="text" ref={(x) => this.inputText = x}/>
<button onClick={this.handleClick}>Enter</button>
</div>
);
}
}
instead of using a button to update the state try this:
<input type="text" onChange={(e) => this.setState({searchInput: e.target.value }) />

How to focus a specific component on page load in React using hooks? [duplicate]

What's the react way of setting focus on a particular text field after the component is rendered?
Documentation seems to suggest using refs, e.g:
Set ref="nameInput" on my input field in the render function, and then call:
this.refs.nameInput.getInputDOMNode().focus();
But where should I call this? I've tried a few places but I cannot get it to work.
#Dhiraj's answer is correct, and for convenience you can use the autoFocus prop to have an input automatically focus when mounted:
<input autoFocus name=...
Note that in jsx it's autoFocus (capital F) unlike plain old html which is case-insensitive.
You should do it in componentDidMount and refs callback instead. Something like this
componentDidMount(){
this.nameInput.focus();
}
class App extends React.Component{
componentDidMount(){
this.nameInput.focus();
}
render() {
return(
<div>
<input
defaultValue="Won't focus"
/>
<input
ref={(input) => { this.nameInput = input; }}
defaultValue="will focus"
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<div id="app"></div>
Focus on mount
If you just want to focus an element when it mounts (initially renders) a simple use of the autoFocus attribute will do.
<input type="text" autoFocus />
Dynamic focus
to control focus dynamically use a general function to hide implementation details from your components.
React 16.8 + Functional component - useFocus hook
const FocusDemo = () => {
const [inputRef, setInputFocus] = useFocus()
return (
<>
<button onClick={setInputFocus} >
Focus
</button>
<input ref={inputRef} />
</>
)
}
const useFocus = () => {
const htmlElRef = useRef(null)
const setFocus = () => {htmlElRef.current && htmlElRef.current.focus()}
return [ htmlElRef, setFocus ]
}
Full Demo
React 16.3 + Class Components - utilizeFocus
class App extends Component {
constructor(props){
super(props)
this.inputFocus = utilizeFocus()
}
render(){
return (
<>
<button onClick={this.inputFocus.setFocus}>
Focus
</button>
<input ref={this.inputFocus.ref}/>
</>
)
}
}
const utilizeFocus = () => {
const ref = React.createRef()
const setFocus = () => {ref.current && ref.current.focus()}
return {setFocus, ref}
}
Full Demo
As of React 0.15, the most concise method is:
<input ref={input => input && input.focus()}/>
If you just want to make autofocus in React, it's simple.
<input autoFocus type="text" />
While if you just want to know where to put that code, answer is in componentDidMount().
v014.3
componentDidMount() {
this.refs.linkInput.focus()
}
In most cases, you can attach a ref to the DOM node and avoid using findDOMNode at all.
Read the API documents here: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
React 16.3 added a new convenient way to handle this by creating a ref in component's constructor and use it like below:
class MyForm extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focus();
}
render() {
return(
<div>
<input ref={this.textInput} />
</div>
);
}
}
For more details about React.createRef, you can check this article in React blog.
Update:
Starting from React 16.8, useRef hook can be used in function components to achieve the same result:
import React, { useEffect, useRef } from 'react';
const MyForm = () => {
const textInput = useRef(null);
useEffect(() => {
textInput.current.focus();
}, []);
return (
<div>
<input ref={textInput} />
</div>
);
};
The React docs now have a section for this. https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute
render: function() {
return (
<TextInput
ref={function(input) {
if (input != null) {
input.focus();
}
}} />
);
},
I just ran into this issue and I'm using react 15.0.1 15.0.2 and I'm using ES6 syntax and didn't quite get what I needed from the other answers since v.15 dropped weeks ago and some of the this.refs properties were deprecated and removed.
In general, what I needed was:
Focus the first input (field) element when the component mounts
Focus the first input (field) element with an error (after submit)
I'm using:
React Container/Presentation Component
Redux
React-Router
Focus the First Input Element
I used autoFocus={true} on the first <input /> on the page so that when the component mounts, it will get focus.
Focus the First Input Element with an Error
This took longer and was more convoluted. I'm keeping out code that isn't relevant to the solution for brevity.
Redux Store / State
I need a global state to know if I should set the focus and to disable it when it was set, so I don't keep re-setting focus when the components re-render (I'll be using componentDidUpdate() to check for setting focus.)
This could be designed as you see fit for you application.
{
form: {
resetFocus: false,
}
}
Container Component
The component will need to have the resetfocus property set and a callBack to clear the property if it ends up setting focus on itself.
Also note, I organized my Action Creators into separate files mostly due to my project is fairly large and I wanted to break them up into more manageable chunks.
import { connect } from 'react-redux';
import MyField from '../presentation/MyField';
import ActionCreator from '../actions/action-creators';
function mapStateToProps(state) {
return {
resetFocus: state.form.resetFocus
}
}
function mapDispatchToProps(dispatch) {
return {
clearResetFocus() {
dispatch(ActionCreator.clearResetFocus());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyField);
Presentation Component
import React, { PropTypes } form 'react';
export default class MyField extends React.Component {
// don't forget to .bind(this)
constructor(props) {
super(props);
this._handleRef = this._handleRef.bind(this);
}
// This is not called on the initial render so
// this._input will be set before this get called
componentDidUpdate() {
if(!this.props.resetFocus) {
return false;
}
if(this.shouldfocus()) {
this._input.focus();
this.props.clearResetFocus();
}
}
// When the component mounts, it will save a
// reference to itself as _input, which we'll
// be able to call in subsequent componentDidUpdate()
// calls if we need to set focus.
_handleRef(c) {
this._input = c;
}
// Whatever logic you need to determine if this
// component should get focus
shouldFocus() {
// ...
}
// pass the _handleRef callback so we can access
// a reference of this element in other component methods
render() {
return (
<input ref={this._handleRef} type="text" />
);
}
}
Myfield.propTypes = {
clearResetFocus: PropTypes.func,
resetFocus: PropTypes.bool
}
Overview
The general idea is that each form field that could have an error and be focused needs to check itself and if it needs to set focus on itself.
There's business logic that needs to happen to determine if the given field is the right field to set focus to. This isn't shown because it will depend on the individual application.
When a form is submitted, that event needs to set the global focus flag resetFocus to true. Then as each component updates itself, it will see that it should check to see if it gets the focus and if it does, dispatch the event to reset focus so other elements don't have to keep checking.
edit
As a side note, I had my business logic in a "utilities" file and I just exported the method and called it within each shouldfocus() method.
Cheers!
This is not longer the best answer. As of v0.13, this.refs may not available until AFTER componentDidMount() runs, in some odd cases.
Just add the autoFocus tag to your input field, as FakeRainBrigand showed above.
Ref. #Dave's comment on #Dhiraj's answer; an alternative is to use the callback functionality of the ref attribute on the element being rendered (after a component first renders):
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
More info
Using React Hooks / Functional components with Typescript, you can use the useRef hook with HTMLInputElement as the generic parameter of useRef:
import React, { useEffect, useRef } from 'react';
export default function MyComponent(): JSX.Element {
const inputReference = useRef<HTMLInputElement>(null);
useEffect(() => {
inputReference.current?.focus();
}, []);
return (
<div>
<input ref={inputReference} />
</div>
);
}
Or if using reactstrap, supply inputReference to innerRef instead of ref:
import React, { useEffect, useRef } from 'react';
import { Input } from 'reactstrap';
export default function MyComponent(): JSX.Element {
const inputReference = useRef<HTMLInputElement>(null);
useEffect(() => {
inputReference.current?.focus();
}, []);
return (
<div>
<Input innerRef={inputReference} />
</div>
);
}
Note that none of these answers worked for me with a material-ui TextField component. Per How to set focus to a materialUI TextField? I had to jump through some hoops to get this to work:
const focusUsernameInputField = input => {
if (input) {
setTimeout(() => {input.focus()}, 100);
}
};
return (
<TextField
hintText="Username"
floatingLabelText="Username"
ref={focusUsernameInputField}
/>
);
This is the proper way, how to autofocus. When you use callback instead of string as ref value, it is automatically called. You got your ref available than without the need of touching the DOM using getDOMNode
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._input.focus();
},
You don't need getInputDOMNode?? in this case...
Just simply get the ref and focus() it when component gets mounted -- componentDidMount...
import React from 'react';
import { render } from 'react-dom';
class myApp extends React.Component {
componentDidMount() {
this.nameInput.focus();
}
render() {
return(
<div>
<input ref={input => { this.nameInput = input; }} />
</div>
);
}
}
ReactDOM.render(<myApp />, document.getElementById('root'));
You can put that method call inside the render function. Or inside the life cycle method, componentDidUpdate
I have same problem but I have some animation too, so my colleague suggest to use window.requestAnimationFrame
this is ref attribute of my element:
ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
AutoFocus worked best for me. I needed to change some text to an input with that text on double click so this is what I ended up with:
<input autoFocus onFocus={this.setCaretToEnd} value={this.state.editTodo.value} onDoubleClick={this.updateTodoItem} />
NOTE: To fix the issue where React places the caret at the beginning of the text use this method:
setCaretToEnd(event) {
var originalText = event.target.value;
event.target.value = '';
event.target.value = originalText;
}
Found here:
https://coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js
<input type="text" autoFocus />
always try the simple and basic solution first, works for me.
To move focus to a newly created element, you can store the element's ID in the state and use it to set autoFocus. e.g.
export default class DefaultRolesPage extends React.Component {
addRole = ev => {
ev.preventDefault();
const roleKey = this.roleKey++;
this::updateState({
focus: {$set: roleKey},
formData: {
roles: {
$push: [{
id: null,
name: '',
permissions: new Set(),
key: roleKey,
}]
}
}
})
}
render() {
const {formData} = this.state;
return (
<GridForm onSubmit={this.submit}>
{formData.roles.map((role, idx) => (
<GridSection key={role.key}>
<GridRow>
<GridCol>
<label>Role</label>
<TextBox value={role.name} onChange={this.roleName(idx)} autoFocus={role.key === this.state.focus}/>
</GridCol>
</GridRow>
</GridSection>
))}
</GridForm>
)
}
}
This way none of the textboxes get focus on page load (like I want), but when you press the "Add" button to create a new record, then that new record gets focus.
Since autoFocus doesn't "run" again unless the component gets remounted, I don't have to bother unsetting this.state.focus (i.e. it won't keep stealing focus back as I update other states).
Simple solution without autofocus:
<input ref={ref => ref && ref.focus()}
onFocus={(e)=>e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length)}
/>
ref triggers focus, and that triggers onFocus to calculate the end and set the cursor accordingly.
Ben Carp solution in typescript
React 16.8 + Functional component - useFocus hook
export const useFocus = (): [React.MutableRefObject<HTMLInputElement>, VoidFunction] => {
const htmlElRef = React.useRef<HTMLInputElement>(null);
const setFocus = React.useCallback(() => {
if (htmlElRef.current) htmlElRef.current.focus();
}, [htmlElRef]);
return React.useMemo(() => [htmlElRef, setFocus], [htmlElRef, setFocus]);
};
Warning: ReactDOMComponent: Do not access .getDOMNode() of a DOM node; instead, use the node directly. This DOM node was rendered by App.
Should be
componentDidMount: function () {
this.refs.nameInput.focus();
}
The simplest answer is add the ref="some name" in the input text element and call the below function.
componentDidMount(){
this.refs.field_name.focus();
}
// here field_name is ref name.
<input type="text" ref="field_name" />
After trying a lot of options above with no success I've found that It was as I was disabling and then enabling the input which caused the focus to be lost.
I had a prop sendingAnswer which would disable the Input while I was polling the backend.
<Input
autoFocus={question}
placeholder={
gettingQuestion ? 'Loading...' : 'Type your answer here...'
}
value={answer}
onChange={event => dispatch(updateAnswer(event.target.value))}
type="text"
autocomplete="off"
name="answer"
// disabled={sendingAnswer} <-- Causing focus to be lost.
/>
Once I removed the disabled prop everything started working again.
Read almost all the answer but didnt see a getRenderedComponent().props.input
Set your text input refs
this.refs.username.getRenderedComponent().props.input.onChange('');
According to the updated syntax, you can use this.myRref.current.focus()
Focus using createRef for functional components
To developers using Functional Components. This seems to suit. Focus happens on inputfield after clicking on the button. I've attached CodeSandbox link too.
import React from 'react';
export default function App() {
const inputRef = React.createRef();
return <>
<input ref={inputRef} type={'text'} />
<button onClick={() => {if (inputRef.current) { inputRef.current.focus() }}} >
Click Here
</button>
</>
}
https://codesandbox.io/s/blazing-http-hfwp9t
That one worked for me:
<input autoFocus={true} />
Updated version you can check here
componentDidMount() {
// Focus to the input as html5 autofocus
this.inputRef.focus();
}
render() {
return <input type="text" ref={(input) => { this.inputRef = input }} />
})
Since there is a lot of reasons for this error I thought that I would also post the problem I was facing. For me, problem was that I rendered my inputs as content of another component.
export default ({ Content }) => {
return (
<div className="container-fluid main_container">
<div className="row">
<div className="col-sm-12 h-100">
<Content /> // I rendered my inputs here
</div>
</div>
</div>
);
}
This is the way I called the above component:
<Component Content={() => {
return (
<input type="text"/>
);
}} />

ReactJS: doing calculations to setState, and updating

I'd like to have two input numeric fields, value1 and value2 and add the values of those two fields. The sum will then be saved in this.state.sum. I also don't want to use a "submit" button. Some code:
import React, { Component } from 'react';
import addNumbers from "./components/addNumbers"
class App extends Component {
constructor() {
super()
this.state = {
value1: 10,
value2: 3,
sum: 13
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
//first setState call works fine
this.setState({[event.target.name]: event.target.value})
//call addNumbers function
const sum = addNumbers(this.state.value1, this.statevalue2)
//this second setState() call will lag by one step
this.setState({sum: sum})
console.log(newBarData)
}
render() {
return (
<div>
<form>
<input name="value1" type="number" placeholder="10" onBlur={this.handleChange} />
<input name="value2" type="number" placeholder="3" onBlur={this.handleChange} />
</form>
</div>
);
}
}
export default App;
What happens is: the second setState() call won't be effected until I make a second change on the page. This is quite a common issue, but I'm not sure how to work around it. I'd like for it to be able to proc immediately after the user updates the form. In the actual use-case, there'll be some calculations based on user-input values, then visualized on a graph (plotly.js), and I want to be able to update the graph "live" after each input field change.
You can use currying to create different handler in one piece of code (see: makeHandleChange). Then you can use componentDidUpdate to check if the value of your inputs changed to update your sum state value.
import React, { Component } from 'react';
import addNumbers from "./components/addNumbers"
class App extends Component {
state = {
value1: 10,
value2: 3,
sum: 13
}
componentDidUpdate(lastProps, lastState) {
const valueChanged = this.state.value1 !== lastState.value1 || this.state.value2 != lastState.value2
if (valueChanged) {
const sum = addNumbers(this.state.value1, this.state.value2)
this.setState({ sum })
}
}
makeHandleChange = id => ({ target: { value } }) => {
this.setState({
[`value${id}`]: value
})
}
render() {
return (
<div>
<form>
<input name="value1" type="number" placeholder="10" onBlur={this.makeHandleChange(1)} />
<input name="value2" type="number" placeholder="3" onBlur={this.makeHandleChange(2)} />
<div>the sum is: {this.state.sum}</div>
</form>
</div>
);
}
}
export default App;

Wrapping a Component means it loses focus on rerender

I have a long form in react. Before, it had a bunch of components that were defined as such:
<input
type='text'
value={this.state.form.nameOfFormField}
onChange={this.updateForm('nameOfFormField')} />
Where updateForm is a function in the form of (field) => (e) => {}, to make code reuse easier.
I wanted to make this easier to maintain, so I created a component, SpecialInput, which was defined as such:
const SpecialInputBuilder = (form, onChange) => ({ field, ..props }) => (
<input
type='text'
value={form[field]}
onChange={onChange(field)}
{...props} />
)
Now, I could define the Input during render like so:
const SpecialInput = SpecialInputBuilder(this.state.form, this.updateForm)
And use it in the component like this:
<SpecialInput field='nameOfFormField' />
Obviously, this is much more succinct. But this also means that the input field will drop focus every time input is entered into the field (i.e., when updateForm is called), because SpecialInput is defined every time the render function is called. Defining a key to each element does not seem to at all alleviate the problem. How can I fix this while still using this simpler component? Is there a middle ground?
Why not just change your input builder to just be a react component?
const SpecialInput = (props) => {
return (
<input
value={props.form[props.field]}
{...props}
type={props.type || 'text'}
onChange={() => props.onChange(props.field)}
/>
)
}
and just use it the same way.
<SpecialInput field='nameOfFormField' onChange={this.updateForm} form={this.state.form} />
I had a similar approach but ended up changing it to this;
(1) Input typer child component:
import React, { Component } from 'react';
class FreeTextField extends Component {
inputValueFn(e) {
this.props.userInput(this.props.responseObject, e.target.value);
}
render() {
return (
<div className="input-group">
<label>{this.props.buttonText ? this.props.buttonText : "Firstname"}</label>
<input type={this.props.type} placeholder="" className="form-control" defaultValue={this.props.defaultValue} onChange={this.inputValueFn.bind(this)} />
</div>
);
}
}
export default FreeTextField;
(2) From the parent component you can specify all relavent child attr via props
// import
import FreeTextField from './pathTo/FreeTextField';
// Initial state
this.state = {
responseObject: {}
}
// onChange it updates the responseObject
userInput(fieldKey,value) {
let responseObject = this.state.responseObject;
responseObject[fieldKey] = value;
this.setState({responseObject:responseObject});
}
// component render()
<FreeTextField
buttonText="First Name"
type="text"
formObjectKey="first_name"
userInput{this.userInput.bind(this)} />
The main issue is that your onChange call is executing as soon as it's rendered, instead of a reference to a function to be called when the input changes.
// this executes immediately
onChange={onChange(field)}
// this is a reference to the function with a prop prepended
onChange={onChange.bind(this,field)}

Categories

Resources