How to get "key" prop from React element (on change)? - javascript

I want to get option's value and key when select onChange.
I know I can get option's value simplicity used event.target.value in onChangeOption function, but how can I get key?
<select onChange={this.onChangeOption} value={country}>
{countryOptions.map((item, key) =>
<option key={key} value={item.value}>
{item.name}
</option>
)}
</select>

You will need to pass value in key as a different prop.
From docs:
Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
Read: https://reactjs.org/docs/lists-and-keys.html

Passing key as a prop works obviously, but much quicker way could be to include the key as a custom attribute in your html.
class App extends React.Component {
constructor(props) {
super(props);
this.onSelect = this.onSelect.bind(this);
}
onSelect(event) {
const selectedIndex = event.target.options.selectedIndex;
console.log(event.target.options[selectedIndex].getAttribute('data-key'));
}
render() {
return (
<div>
<select onChange = {this.onSelect}>
<option key="1" data-key="1">One</option>
<option key="2" data-key="2">Two</option> </select>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

A simple way of doing this is:
const functionCall = (event) => {
console.log(event.target.getAttribute('a-key'));
}
<button a-key={1} onClick={functionCall}>Press Me</button>
I put onClick but you can use any event.

You can pass anything through value. I think this solves your problem.
<select onChange={this.handleChange}>
{this.state.countryOptions.map((item, key) =>
<option key={key}
value={JSON.stringify({key, value:item.value})}>
//passing index along with value
{item.value}
</option>
)}
</select>
handleChange(e) {
let obj = JSON.parse(e.target.value)
// gives object{ key:country index, value: country value}
}

Imagine a component like this:
<Component data={[{id:'a23fjeZ', name="foo"}, ...]}`
Which renders a list of inputs, and gets in a data prop which is a collection (Array of Objects):
function Component ( props ){
// cached handler per unique key. A self-invoked function with a "cache" object
const onChange = (cache => param => {
if( !cache[param] )
cache[param] = e =>
console.log(param, e.target.name, e.target.value)
return cache[param];
}
)({});
return props.data.map(item =>
<input key={item.id} name={item.name} onChange={onChange(item.id)} />
}
}
As you can see, the key isn't being accessed, but is passed into a currying function which is handling the caching internally, to prevent "endless" creation of functions on re-renders.

I'm a beginner and have battle with this for days now!
Now, I will be happy to share you my final answer!
This is really easy -All you got to do is to declare an anonymous function! for an onClick on the item you wanna detect its key!
e.g
data.map((item) => (<div
className = "newItem" key = {item.id} onClick = {() = displayKey(item.id)}
>{item.value}</div>))
then your function can be thus;
will display any "val" passed in
const displayKey = (val) => {
console.log(val)
}
I hope I was able to help!
battling with a problem can be a pain in the ass!
Kind Regards .

So you do need to pass the key into the <option> as a prop, but since the <select> is a native field and handles changes internally it gets a little hard to get that key value back out.
Lets start one issue at a time, passing the prop into the option could be as simple as wrapping the option component like so and using the index prop as the new key prop.
const CustomOption = ({ value, children, index }) => (
<option key={index} value={value}>{value}</option>
);
Also note that we're creating a custom component wrapper above to swallow the index prop from being applied to <option /> itself as react doesnt like unknown props on dom elements.
Now if we could handle the selected event inside the option we would be done, but we can't do that. so we need to make a custom select as well:
class CustomSelect extends React.Component {
static propTypes = {
value: PropTypes.object,
onChange: PropTypes.func,
}
handleChanged = (e) => {
const newValue = e.target.value;
let newKey;
// iterate through our children searching for the <CustomOption /> that was just selected
React.children.forEach(this.children, (c) => {
if (c.props && c.props.index && c.props.value === newValue) {
newKey = c.props.key;
}
});
this.props.onChange(e, newKey);
}
render() {
return (
<select value={this.props.value} onChange={this.handleChanged}>
{this.props.children}
</select>
);
}
}
it has two props value, and onChange. Notice that we intercept the change event in order to find the index (the key) and we pass it along to the parent as the second parameter. This is not very nice but I can't think of another easy way to do this while still using the native <select> element.
Note you need to replace your usages of <select> and <optoin> to use these new classes, and assign the index prop along with the key prop on the option.

Related

React PropTypes warning for function component with a prop that has a default value [duplicate]

I want to get option's value and key when select onChange.
I know I can get option's value simplicity used event.target.value in onChangeOption function, but how can I get key?
<select onChange={this.onChangeOption} value={country}>
{countryOptions.map((item, key) =>
<option key={key} value={item.value}>
{item.name}
</option>
)}
</select>
You will need to pass value in key as a different prop.
From docs:
Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
Read: https://reactjs.org/docs/lists-and-keys.html
Passing key as a prop works obviously, but much quicker way could be to include the key as a custom attribute in your html.
class App extends React.Component {
constructor(props) {
super(props);
this.onSelect = this.onSelect.bind(this);
}
onSelect(event) {
const selectedIndex = event.target.options.selectedIndex;
console.log(event.target.options[selectedIndex].getAttribute('data-key'));
}
render() {
return (
<div>
<select onChange = {this.onSelect}>
<option key="1" data-key="1">One</option>
<option key="2" data-key="2">Two</option> </select>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
A simple way of doing this is:
const functionCall = (event) => {
console.log(event.target.getAttribute('a-key'));
}
<button a-key={1} onClick={functionCall}>Press Me</button>
I put onClick but you can use any event.
You can pass anything through value. I think this solves your problem.
<select onChange={this.handleChange}>
{this.state.countryOptions.map((item, key) =>
<option key={key}
value={JSON.stringify({key, value:item.value})}>
//passing index along with value
{item.value}
</option>
)}
</select>
handleChange(e) {
let obj = JSON.parse(e.target.value)
// gives object{ key:country index, value: country value}
}
Imagine a component like this:
<Component data={[{id:'a23fjeZ', name="foo"}, ...]}`
Which renders a list of inputs, and gets in a data prop which is a collection (Array of Objects):
function Component ( props ){
// cached handler per unique key. A self-invoked function with a "cache" object
const onChange = (cache => param => {
if( !cache[param] )
cache[param] = e =>
console.log(param, e.target.name, e.target.value)
return cache[param];
}
)({});
return props.data.map(item =>
<input key={item.id} name={item.name} onChange={onChange(item.id)} />
}
}
As you can see, the key isn't being accessed, but is passed into a currying function which is handling the caching internally, to prevent "endless" creation of functions on re-renders.
I'm a beginner and have battle with this for days now!
Now, I will be happy to share you my final answer!
This is really easy -All you got to do is to declare an anonymous function! for an onClick on the item you wanna detect its key!
e.g
data.map((item) => (<div
className = "newItem" key = {item.id} onClick = {() = displayKey(item.id)}
>{item.value}</div>))
then your function can be thus;
will display any "val" passed in
const displayKey = (val) => {
console.log(val)
}
I hope I was able to help!
battling with a problem can be a pain in the ass!
Kind Regards .
So you do need to pass the key into the <option> as a prop, but since the <select> is a native field and handles changes internally it gets a little hard to get that key value back out.
Lets start one issue at a time, passing the prop into the option could be as simple as wrapping the option component like so and using the index prop as the new key prop.
const CustomOption = ({ value, children, index }) => (
<option key={index} value={value}>{value}</option>
);
Also note that we're creating a custom component wrapper above to swallow the index prop from being applied to <option /> itself as react doesnt like unknown props on dom elements.
Now if we could handle the selected event inside the option we would be done, but we can't do that. so we need to make a custom select as well:
class CustomSelect extends React.Component {
static propTypes = {
value: PropTypes.object,
onChange: PropTypes.func,
}
handleChanged = (e) => {
const newValue = e.target.value;
let newKey;
// iterate through our children searching for the <CustomOption /> that was just selected
React.children.forEach(this.children, (c) => {
if (c.props && c.props.index && c.props.value === newValue) {
newKey = c.props.key;
}
});
this.props.onChange(e, newKey);
}
render() {
return (
<select value={this.props.value} onChange={this.handleChanged}>
{this.props.children}
</select>
);
}
}
it has two props value, and onChange. Notice that we intercept the change event in order to find the index (the key) and we pass it along to the parent as the second parameter. This is not very nice but I can't think of another easy way to do this while still using the native <select> element.
Note you need to replace your usages of <select> and <optoin> to use these new classes, and assign the index prop along with the key prop on the option.

React passing value from dropdown back to parent component

My parent component looks like:
<div>
<Dropdown items={companiesData} handler={handleClick} />
....//More stuff
</div>
companiesData is an array of items with id, companyName etc.
I am creating my dropdown this way:
const Dropwdown = ({ items, handler }) => {
return (
<select onChange={handler}>
{items.map(({ id, value, companyName, companyType }) => (
<option
key={id}
value={value}
>
{`${companyName}, ${companyType} `}
</option>
))}
</select>
)
}
I know that from the handleClick function I can access e.target.value and get the value of the dropdown, but what if I want to get the whole object of that selected value (e.g. containing id, value, companyName etc.)and pass it back to the parent component?
in Dropdown, add value property to select and use the id like value={this.state.selectedValue}.
So you will have that value in ev.target.value.
Then, in your parent, you can do something like: companiesData.filter(company => company.id === ev.target.value). And you have the info there.
and of course set the selectedValue (using hooks or normal setState)
Another option (if you don't want to do filtering) is to simply send e.target to your handler instead of e.target.value.
In your handler, retrieve the info you need like this:
const parentHandler = target => {
const targetOptions = target.options;
const selectedValue = target.value;
console.log("selected value", selectedValue);
console.log("all html options array", targetOptions);
console.log("selected option html", targetOptions[target.selectedIndex]);
console.log(
"selected option name",
targetOptions[target.selectedIndex].getAttribute("name")
);
};
see a demo here

How to add the input field inside the select option using ant design and react

I created select option using ant design .But I need create editable cell inside the select option.
This my select option code
<Select
showSearch
style={{ width: 400 }}
placeholder="Select a Bank"
optionFilterProp="children"
onChange={this.handleChange.bind(this)}
>
<option value="1">Bank1</option>
<option value="2"> Bank2</option>
<option value="3"> Bank3</option>
</Select>
And onChange functions is
handleChange(value) {
console.log(`selected ${value}`);
this.setState({
bank:value,
});
}
Can you help me?
I suppose the question is whether or not this is an editable list.
The Select component has a mode prop that can be used to change the functionality with the following options:
'default' | 'multiple' | 'tags' | 'combobox'
Using the tags mode would allow you to add and remove items and generate a tokenized list when the form is submitted.
If you are looking at a fixed list and then wanting to create new items to add to the list:
If you want to be able to add new items to the list, this doesn't exist currently, as far as I am aware.
You may be able to refashion something from the Ant Design Pro components, or otherwise come up with a solution where:
when "create" is selected, you toggle the Select for an Input
when the input is submitted/blurred update the Options list, toggle the Select/Input once more and submit the value to the back-end.
I hope this helps.
You don't need to do that actually. All you need to do is to use component state and two simple callback functions ant design provides for select.
So let's assume you need to allow users not to also search for existing values inside a Select but if it didn't exist they can choose a new one. So here's what I'd do:
Inside render() method:
<Select
showSearch
value={this.title}
filterOption={true}
onSearch={this.handleSearch}
onFocus={this.handleFocus}
style={{ width: "100%" }}>
{this.titles.map((title) => (
<Select.Option key={title}>{title}</Select.Option>
))}
</Select>
Where this.titles = ["something", "else"].
Then Inside this.handleSearchand this.handleFocus I'd write:
protected handleSearch = (value: string) => {
this.setState({ titles: value && value !== "" ? [...this.titles, value] : fileTitles });
};
protected handleFocus = () => {
this.setState({ this.titles });
};
What we're basically doing is to populate the options we're iterating over inside the Select with this.titles in the state of the component itself (don't confuse it with Redux or MobX) when user opens the selector and once user searches for anything that would be added to options as well. With this approach you won't need an input or a switch to show/hide inputs. Hope it helps.
You could use another modal to input the additional value.
Check this : https://codesandbox.io/s/antdselectaddoption-7fov7
Code from mamsoudi throws Errors, so i took his idea and made my own component that i'm sharing with you.
import React from 'react';
import {Select} from "antd";
class FieldSelectAndCustomText extends React.Component {
constructor(props) {
super(props);
this.initialTitles = ["something", "else"];
this.state = {
titles: this.initialTitles,
currentValue: null,
};
}
handleSearch = (value) => {
const titles = this.state.titles;
for (let i = 0; i < titles.length; i++) {
const isSearchValueInState = new RegExp(value).test(titles[i]);
if (!isSearchValueInState) {
this.setState({
titles: [...this.initialTitles, value],
currentValue: value
});
break;
}
}
};
handleChange = (value) => {
this.setState(prev => ({...prev, currentValue: value}));
}
render () {
return (
<div>
<Select
showSearch
value={this.state.currentValue}
filterOption={true}
onSearch={this.handleSearch}
onChange={this.handleChange}
onFocus={this.handleFocus}
style={{ width: "100%" }}>
{this.state.titles.map((title) => (
<Select.Option value={title} key={title}>{title}</Select.Option>
))}
</Select>
</div>
);
}
}

How to listen to onChange of the Field component in React-Final-Form?

Redux-form "Field" component provides onChange property. A callback that will be called whenever an onChange event is fired from the underlying input. This callback allows to get "newValue" and "previousValue" for the Field.
React-final-form "Field" component doesn't have this property.
So, how I can get the same functionality?
React-final-form handles this functionality with a tiny external package.
Basically it is an additional component to add inside the form that binds to the element using its name:
<Field name="foo" component="input" type="checkbox" />
<OnChange name="foo">
{(value, previous) => {
// do something
}}
</OnChange>
The current documentation can be found here:
https://github.com/final-form/react-final-form-listeners#onchange
The idea under change detection is to subscribe to value changes of Field and call your custom onChange handler when value actually changes. I prepared simplified example where you can see it in action. Details are in MyField.js file.
As the result you can use it just as with redux-form:
<MyField
component="input"
name="firstName"
onChange={(val, prevVal) => console.log(val, prevVal)}
/>
2022 JANUARY UPDATE
While the code above still works (check the sandbox version) there is a case when the solutions requires more tweeks around it.
Here is an updated sandbox with an implementation via the hooks. It's based on a useFieldValue hook and OnChange component as a consumer of this hook. But the hook itself can be used separately when you need previous value between re-renders. This solution doesn't rely on meta.active of the field.
// useFieldValue.js
import { useEffect, useRef } from "react";
import { useField } from "react-final-form";
const usePrevious = (val) => {
const ref = useRef(val);
useEffect(() => {
ref.current = val;
}, [val]);
return ref.current;
};
const useFieldValue = (name) => {
const {
input: { value }
} = useField(name, { subscription: { value: true } });
const prevValue = usePrevious(value);
return [value, prevValue];
};
export default useFieldValue;
// OnChange.js
import { useEffect } from "react";
import useFieldValue from "./useFieldValue";
export default ({ name, onChange }) => {
const [value, prevValue] = useFieldValue(name);
useEffect(() => {
if (value !== prevValue) {
onChange(value, prevValue);
}
}, [onChange, value, prevValue]);
return null;
};
Another nice option is this answer: https://stackoverflow.com/a/56495998/3647991
I haven't used redux-form, but I added a super simple wrapper around the Field component to listen to onChange like this:
const Input = props => {
const {
name,
validate,
onChange,
...rest
} = props;
return (
<Field name={name} validate={validate}>
{({input, meta}) => {
return (
<input
{...input}
{...rest}
onChange={(e) => {
input.onChange(e); //final-form's onChange
if (onChange) { //props.onChange
onChange(e);
}
}}
/>
)}}
</Field>
);
};
One could use the Field's parse attribute and provide a function that does what you need with the value:
<Field
parse={value => {
// Do what you want with `value`
return value;
}}
// ...
/>
You need to use the ExternalModificationDetector component to listen for changes on the field component like this:
<ExternalModificationDetector name="abc">
{externallyModified => (
<BooleanDecay value={externallyModified} delay={1000}>
{highlight => (
<Field
//field properties here
/>
)}
</BooleanDecay>
)}
</ExternalModificationDetector>
By wrapping a stateful ExternalModificationDetector component in a
Field component, we can listen for changes to a field's value, and by
knowing whether or not the field is active, deduce when a field's
value changes due to external influences.
Via - React-Final-Form Github Docs
Here is a sandbox example provided in the React-Final-Form Docs: https://codesandbox.io/s/3x989zl866

How to access a child's state in React

I have the following structure:
FormEditor - holds multiple instances of FieldEditor
FieldEditor - edits a field of the form and saving various values about it in its state
When a button is clicked within FormEditor, I want to be able to collect information about the fields from all FieldEditor components, information that's in their state, and have it all within FormEditor.
I considered storing the information about the fields outside of FieldEditor's state and put it in FormEditor's state instead. However, that would require FormEditor to listen to each of its FieldEditor components as they change and store their information in its state.
Can't I just access the children's state instead? Is it ideal?
Just before I go into detail about how you can access the state of a child component, please make sure to read Markus-ipse's answer regarding a better solution to handle this particular scenario.
If you do indeed wish to access the state of a component's children, you can assign a property called ref to each child. There are now two ways to implement references: Using React.createRef() and callback refs.
Using React.createRef()
This is currently the recommended way to use references as of React 16.3 (See the documentation for more information). If you're using an earlier version then see below regarding callback references.
You'll need to create a new reference in the constructor of your parent component and then assign it to a child via the ref attribute.
class FormEditor extends React.Component {
constructor(props) {
super(props);
this.FieldEditor1 = React.createRef();
}
render() {
return <FieldEditor ref={this.FieldEditor1} />;
}
}
In order to access this kind of ref, you'll need to use:
const currentFieldEditor1 = this.FieldEditor1.current;
This will return an instance of the mounted component so you can then use currentFieldEditor1.state to access the state.
Just a quick note to say that if you use these references on a DOM node instead of a component (e.g. <div ref={this.divRef} />) then this.divRef.current will return the underlying DOM element instead of a component instance.
Callback Refs
This property takes a callback function that is passed a reference to the attached component. This callback is executed immediately after the component is mounted or unmounted.
For example:
<FieldEditor
ref={(fieldEditor1) => {this.fieldEditor1 = fieldEditor1;}
{...props}
/>
In these examples the reference is stored on the parent component. To call this component in your code, you can use:
this.fieldEditor1
and then use this.fieldEditor1.state to get the state.
One thing to note, make sure your child component has rendered before you try to access it ^_^
As above, if you use these references on a DOM node instead of a component (e.g. <div ref={(divRef) => {this.myDiv = divRef;}} />) then this.divRef will return the underlying DOM element instead of a component instance.
Further Information
If you want to read more about React's ref property, check out this page from Facebook.
Make sure you read the "Don't Overuse Refs" section that says that you shouldn't use the child's state to "make things happen".
If you already have an onChange handler for the individual FieldEditors I don't see why you couldn't just move the state up to the FormEditor component and just pass down a callback from there to the FieldEditors that will update the parent state. That seems like a more React-y way to do it, to me.
Something along the line of this perhaps:
const FieldEditor = ({ value, onChange, id }) => {
const handleChange = event => {
const text = event.target.value;
onChange(id, text);
};
return (
<div className="field-editor">
<input onChange={handleChange} value={value} />
</div>
);
};
const FormEditor = props => {
const [values, setValues] = useState({});
const handleFieldChange = (fieldId, value) => {
setValues({ ...values, [fieldId]: value });
};
const fields = props.fields.map(field => (
<FieldEditor
key={field}
id={field}
onChange={handleFieldChange}
value={values[field]}
/>
));
return (
<div>
{fields}
<pre>{JSON.stringify(values, null, 2)}</pre>
</div>
);
};
// To add the ability to dynamically add/remove fields, keep the list in state
const App = () => {
const fields = ["field1", "field2", "anotherField"];
return <FormEditor fields={fields} />;
};
Original - pre-hooks version:
class FieldEditor extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
const text = event.target.value;
this.props.onChange(this.props.id, text);
}
render() {
return (
<div className="field-editor">
<input onChange={this.handleChange} value={this.props.value} />
</div>
);
}
}
class FormEditor extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleFieldChange = this.handleFieldChange.bind(this);
}
handleFieldChange(fieldId, value) {
this.setState({ [fieldId]: value });
}
render() {
const fields = this.props.fields.map(field => (
<FieldEditor
key={field}
id={field}
onChange={this.handleFieldChange}
value={this.state[field]}
/>
));
return (
<div>
{fields}
<div>{JSON.stringify(this.state)}</div>
</div>
);
}
}
// Convert to a class component and add the ability to dynamically add/remove fields by having it in state
const App = () => {
const fields = ["field1", "field2", "anotherField"];
return <FormEditor fields={fields} />;
};
ReactDOM.render(<App />, document.body);
As the previous answers said, try to move the state to a top component and modify the state through callbacks passed to its children.
In case that you really need to access to a child state that is declared as a functional component (hooks) you can declare a ref in the parent component, and then pass it as a ref attribute to the child, but you need to use React.forwardRef and then the hook useImperativeHandle to declare a function you can call in the parent component.
Take a look at the following example:
const Parent = () => {
const myRef = useRef();
return <Child ref={myRef} />;
}
const Child = React.forwardRef((props, ref) => {
const [myState, setMyState] = useState('This is my state!');
useImperativeHandle(ref, () => ({getMyState: () => {return myState}}), [myState]);
})
Then you should be able to get myState in the Parent component by calling:
myRef.current.getMyState();
It's 2020 and lots of you will come here looking for a similar solution but with Hooks (they are great!) and with the latest approaches in terms of code cleanliness and syntax.
So as previous answers had stated, the best approach to this kind of problem is to hold the state outside of child component fieldEditor. You could do that in multiple ways.
The most "complex" is with a global context (state) that both parent and children could access and modify. It's a great solution when components are very deep in the tree hierarchy and so it's costly to send props in each level.
In this case I think it's not worth it, and a more simple approach will bring us the results we want, just using the powerful React.useState().
An approach with a React.useState() hook - way simpler than with Class components
As said, we will deal with changes and store the data of our child component fieldEditor in our parent fieldForm. To do that we will send a reference to the function that will deal and apply the changes to the fieldForm state, you could do that with:
function FieldForm({ fields }) {
const [fieldsValues, setFieldsValues] = React.useState({});
const handleChange = (event, fieldId) => {
let newFields = { ...fieldsValues };
newFields[fieldId] = event.target.value;
setFieldsValues(newFields);
};
return (
<div>
{fields.map(field => (
<FieldEditor
key={field}
id={field}
handleChange={handleChange}
value={fieldsValues[field]}
/>
))}
<div>{JSON.stringify(fieldsValues)}</div>
</div>
);
}
Note that React.useState({}) will return an array with position 0 being the value specified on call (Empty object in this case), and position 1 being the reference to the function
that modifies the value.
Now with the child component, FieldEditor, you don't even need to create a function with a return statement. A lean constant with an arrow function will do!
const FieldEditor = ({ id, value, handleChange }) => (
<div className="field-editor">
<input onChange={event => handleChange(event, id)} value={value} />
</div>
);
Aaaaand we are done, nothing more. With just these two slim functional components we have our end goal "access" our child FieldEditor value and show it off in our parent.
You could check the accepted answer from 5 years ago and see how Hooks made React code leaner (by a lot!).
Hope my answer helps you learn and understand more about Hooks, and if you want to check a working example here it is.
Now you can access the InputField's state which is the child of FormEditor.
Basically, whenever there is a change in the state of the input field (child), we are getting the value from the event object and then passing this value to the Parent where in the state in the Parent is set.
On a button click, we are just printing the state of the input fields.
The key point here is that we are using the props to get the input field's id/value and also to call the functions which are set as attributes on the input field while we generate the reusable child input fields.
class InputField extends React.Component{
handleChange = (event)=> {
const val = event.target.value;
this.props.onChange(this.props.id , val);
}
render() {
return(
<div>
<input type="text" onChange={this.handleChange} value={this.props.value}/>
<br/><br/>
</div>
);
}
}
class FormEditorParent extends React.Component {
state = {};
handleFieldChange = (inputFieldId , inputFieldValue) => {
this.setState({[inputFieldId]:inputFieldValue});
}
// On a button click, simply get the state of the input field
handleClick = ()=>{
console.log(JSON.stringify(this.state));
}
render() {
const fields = this.props.fields.map(field => (
<InputField
key={field}
id={field}
onChange={this.handleFieldChange}
value={this.state[field]}
/>
));
return (
<div>
<div>
<button onClick={this.handleClick}>Click Me</button>
</div>
<div>
{fields}
</div>
</div>
);
}
}
const App = () => {
const fields = ["field1", "field2", "anotherField"];
return <FormEditorParent fields={fields} />;
};
ReactDOM.render(<App/>, mountNode);
You may access the child state by passing a callback to the child component.
const Parent = () => {
return (
<Child onSubmit={(arg) => {
console.log('accessing child state from parent callback: ', arg)
}}
/>
)
}
const Child = ({onSubmit}) => {
const [text, setText] = useState('');
return (
<>
<input value={text} onChange={setText}>
<button onClick={() => onSubmit(text)} />
</>
)
}
Now if you click the button in the child component, you will execute the function passed from the parent and have access to the child component's state variables.

Categories

Resources