how to pass an event from a child component to parent component back down to another child in React - javascript

Lets say for instance that I have three components in React, an App (the parent component), a button component and a component that is meant to display something, can be anything doesn't really matter. Lets say in the button component is activated, how would I pass the information (ie that the event actually happened) to the App parent component back down to the other child component to let it know a specific event happened to display some message?

this is how I would go about dong this using hooks :
const Parent=(props)=>{
[eventHappend,setEventHappend]=useState(false)
return (
<div>
<Child1 setEventHappend={setEventHappend} />
<Child2 eventHappend={eventHappend} />
</div>
)
}
const Child =({setEventHappend})=>{
return (
<div>
<button onClick={e=>setEventHappend(true)} > click me 1 </button>
</div>
)
}
const Child2 =({eventHappend})=>{
return (
<div>
<button onClick={e=>{/* some code*/ }} > {eventHappend?'event happend':'event didnt happen yet '} </button>
</div>
)
}

There are various ways you can achieve this pass state as props to the child elements (must know before other methods), context or use redux which has a store.
Generally speaking. React has one way data flow, uni directional. As in the parent will hold the state and will be passed to child elements.
Here App holds the state buttonClick which has the information about the event.
const App = () => {
const [ buttonClick, setButtonClick] = React.useState(false);
const messageToBeDispalyed = "The button has been clicked"
return (
<div>
<CustomButton setEventHappened={setButtonClick} />
<DisplayText value = {buttonClick ? messageToBeDispalyed : ""} />
</div>
)
}
const CustomButton = (props) =>{
return <button onClick={(e)=>props.setEventHappened(true)} > Click Me </button>
}
const DisplayText = (props) => {
return <h1> {props.value} </h1>
}

Similar answers to the others, but you would pass down a method to the child from the parent to update the state. But be aware that by doing this will cause a rerender for all of the parent's children.
const Parent = () => {
const [state, setState] = React.useState(false);
const handleClick = value => {
setState(value);
};
return (
<Child state={state} handleClick={handleClick} />
<OtherChild isTrue={state} /> // this component needs data changed by <Child />
)
};
const Child = props => {
const {state, handleClick} = props;
return (
<button onClick={() => handleClick(!state)} >click me</button>
);
};
This way the parent alone handles the state change and provides that method to the child.

as #Loveen Dyall and #Shruti B mentioned you can use RXJS for a more modular approach ,While RxJS is typically thought of as being used with Angular projects, it's a completely separate library that can be used with other JavaScript frameworks like React and Vue.
When using RxJS with React, the way to communicate between components is to use an Observable and a Subject (which is a type of observable), I won't go too much into the details about how observables work here since it's a big subject, but in a nutshell there are two methods that we're interested in: Observable.subscribe() and Subject.next().
learn more about RXJS and Observables : https://blog.logrocket.com/understanding-rxjs-observables/
Observable.subscribe()
The observable subscribe method is used by React components to subscribe to messages that are sent to an observable.
Subject.next()
The subject next method is used to send messages to an observable which are then sent to all React components that are subscribers (a.k.a. observers) of that observable.
here is how you implement it in this use case :
this is called a service and you would put this file in a services folder
import { Subject } from 'rxjs';
const subject = new Subject();
//here where sending { event: eventTitle } , that way you can listen to diffrent events , for example 'INCREMENTED' you could even send values
export const eventsService= {
sendEvent: eventTitle => subject.next({ title: eventTitle }),
getEventNotification: () => subject.asObservable()
};
in your Child 1 component you would subscribe to the observable in useEffect or compoentDidMount if your using class component:
import { eventsService} from '../services';
const Child1 =()=>{
const [child2EventFired,setChild2EventFired]=useState(false)
useEffect(()=>{
let subscription = eventsService.getEventNotification().subscribe(eventTitle =>
{
if (eventTitle=="CHILD2_BUTTON_CLICK" ) {
setChild2EventFired(true)
}else{
setChild2EventFired(false)
}
});
return ()=>{
subscription.unsubscribe();
}
},[])
return <div>
<button> {child2EventFired? 'child2 button event fired':'event not fired yet'} </button>
</div>
}
in your Child 2 component
import { eventsService} from '../services';
const Child2 =()=>{
Child2Click=(e)=>{
//some code,
//then send messages to the observable observable
eventsService.sendEvent('CHILD2_BUTTON_CLICK');
}
return <div>
<button onClick={Child2Click} >click me</button>
</div>
}

Related

Svelte: update parent state from child

In react I can do something like:
App.jsx
const App = () => {
const [state, setState] = useState("old value")
return (
<>
<ChildComponent setState={setState} />
</>
)
}
ChildComponent.jsx
const ChildComponent = ({ setState }) => {
const changeState = () => setState("new value")
return (
<div>
<button onClick={changeState}>Click</button>
</div>
)
}
Then the parent state will be updated.
I don't know how to do the same in Svelte...
I have this:
index.svelte
<script>
import { ChildComponent } from "#components"
let state = "old value"
</script>
<main>
<ChildComponent {state} />
</main>
ChildComponent.svelte
<script>
export let state
const changeState = () => {
// I need to do something like:
state = "new value"
}
</script>
<div>
<button on:click={changeState}>Click</button>
</div>
And see the new value reflected in the parent.
I wanna to do it without use stores... I don't know if it's possible.
Maybe store is the only way to proceed.
I'm ears
There are two ways of doing this in Svelte:
With two-way binding
This will create a sort of connection between parent and child, where updating one will automatically update the other.
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let state = "initial";
</script>
<Child bind:state />
<!-- Child.svelte -->
<script>
export let state;
function changeState() {
state = "new value";
</script>
<button on:click={changeState}>Click</button>
Using events
Just like props go down, events are used to pass informaton up. This can be used if you don't want a strict equivalence between the two states and is a touch more versatile (but also more verbose).
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let state = "initial"
function handleChange(ev) {
state = ev.detail.state
}
</script>
<Child {state} on:change={handleChange} />
<!-- Child.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
export let state
const dispatch = createEventDispatcher()
function changeState() {
// first argument is the event name
// second is an object placed in ev.detail
dispatch('change', { state: "new value" });
}
</script>
<button on:click={changeState}>Click</button>
Which of these to use is up to you and likely depends on the situation, but both benefit that they do not actively rely on what is happening outside the component. If nobody used bind the component doesn't care, it still works. If nobody is listening to this event, again the component doesn't care and keeps on working. Contrast this to the situation where no function is passed, or the function has the wrong signature, suddenly your component is dependent on something that it cannot control which is not a good pattern.

What is the React way of inserting an icon into another component?

I'm trying to create an WithIcon wrapper component which would insert a child (icon) into a wrapped component.
Let's say I have a button:
<Button>Add item</Button>
I want to create a component WithIcon which will be used like this:
<WithIcon i="plus"><Button>Add item</Button></WithIcon>
Ultimately what I want to achieve is this:
<Button className="with-icon"><i className="me-2 bi bi-{icon}"></i>Add item</Button>
Notice the added className and the tag within the Button's body.
I'm trying to figure out how the WithIcon component's code should look like. What is the React way of achieving this result?
The hardest part was the rules of using the WithIcon Will we only have one ?
Will we have only it at the leftmost ? Something like that.
But if we follow your example. We can relatively write something like this for the WithIcon
const WithIcon = ({ i, children }) => {
return React.Children.map(children, (child) => {
return (
<>
<i className={`me-2 bi bi-${i}`}></i>
{React.cloneElement(child, { className: "with-icon" })}
</>
);
});
};
Then we can just use it the way you want it
<WithIcon i="plus"><Button>Add item</Button></WithIcon>
What we do is just looping through the children which in react is any nested jsx you throw in it (Button in our case)
You can find my fiddle here : https://codesandbox.io/s/react-font-awesome-forked-321tz?file=/src/index.js
UPDATE
So my previous answer does not fully meet the end result we want. The will need to be the main parent
The idea is still quite the same as before but here we are infering the type of the component we passed inside the WithIcon This also adds a safeguard when we passed a nested component inside the WithIcon
const WithIcon = ({ i, children }) => {
return React.Children.map(children, (child) => {
const MyType = child.type; // So we can get the Button
return (
<MyType className="with-icon">
<i className={`me-2 bi bi-${i}`}></i>
{(React.cloneElement(child, {}), [child.props.children])}
</MyType>
);
});
};
I think I'll go to sleep I'll update the rest of the explanation at later date.
See the fiddle here :
https://codesandbox.io/s/react-font-awesome-forked-y43fx?file=/src/components/WithIcon.js
Note that this code does not preserved the other props of the passed component, but you can relatively add that by adding {...child.props} at the MyComponent which is just (reflection like?) of infering the component.
Of course also have another option like HOC Enhancers to do this but that adds a bit of complexity to your how to declare your component api. So Pick whats best for ya buddy
Maybe try using a higher order component?
const withIcon = (icon, Component) => ({children, ...props}) => {
return (
<Component className="with-icon" {...props}>
<i className=`me-2 bi bi-${icon}` />
{children}
</Component>
);
}
Then the usage is
const ButtonWithIcon = withIcon("your-icon", Button);
<ButtonWithIcon>Add Item</ButtonWithIcon>
From my experience with react it usually comes down to either using a property inside the component like here (https://material-ui.com/api/button/) or higher order component like what I described.
There are two common patterns used in React for achieving this kind of composition:
Higher-Order Components
Start by defining a component for your button:
const Button = ({ className, children }) => (
<button className={className}>{children}</button>
);
Then the higher-order component can be implemented like this:
const withIcon = (Component) => ({ i, className = '', children, ...props }) => (
<Component {...props} className={`${className} with-icon`}>
<i className={`me-2 bi bi-${i}`} />
{children}
</Component>
);
Usage:
const ButtonWithIcon = withIcon(Button);
<ButtonWithIcon i="plus">Add Item</ButtonWithIcon>
Context
Start by defining the context provider for the icon:
import { createContext } from 'react';
const Icon = createContext('');
const IconProvider = ({ i, children }) => (
<Icon.Provider value={i}>{children}</Icon.Provider>
);
and then your component:
import { useContext } from 'react';
const Button = ({ className = '', children }) => {
const i = useContext(Icon);
if (i) {
className += ' with-icon';
children = (
<>
<i className={`me-2 bi bi-${i}`} />
{children}
</>
);
}
return (
<button className={className}>{children}</button>
);
};
Usage:
<IconProvider i="plus"><Button>Add Item</Button></IconProvider>

React - Change state in child component from another child component

I need to change the state in one child component when a button is clicked in another child component. Both the childs have the same parent component.
import React from "react":
import A from "...";
import B from "...";
class App extends React.Component {
render() {
<div>
<A />
<B />
</div>
}
}
In this example, when a button in component A is pressed, the state in component B needs to be changed.
This application sounds like the perfect use case for "Lifting State Up", i.e. holding the main state in the parent component. Then you basically just pass down handlers (to change the parent state) to component A (this becomes the button's onClick handler), then pass down the state you want to show to component B.
When you click the button, the setState is called in the parent component, which automatically re-renders all children whose props change (including component B).
Here's more detailed info: https://reactjs.org/docs/lifting-state-up.html
EDIT: The reply below reminded me that I should probably add some code to illustrate - but I've made a few changes that simplify things.
import React, {useState} from "react":
import A from "...";
import B from "...";
const App = () => {
const [show, setShow] = useState(false);
function handleToggle() {
// Decouple the implementation of the parent state change from the child
// Pass a function to change the state (async/batching reasons)
setShow(show => !show);
}
return (
<div>
<A show={show} onToggle={handleToggle} />
<B show={show} onToggle={handleToggle} />
</div>
)
}
const A = ({show, onToggle}) => (
<div>
<p>show: {show}</p>
<button onClick={onToggle}>
toggle
</button>
</div>
)
const B = ({show, onToggle}) => (
<div>
<p>show: {show}</p>
<button onClick={onToggle}>
toggle
</button>
</div>
)
So basically we don't care how the state in the parent is changed. We just know that when the button in the child component is clicked, we want to trigger that change. So all we really have to do is call the function passed down via props - we don't have to pass any params.
The parent will then handle any clicks inside the handleToggle function, and you can change this implementation in the future without the child knowing anything. Perhaps you want to change to use mobx to handle state, or run some other code before finally changing the state. Since both are decoupled, you're all good! I've also adjusted setShow to use a function (benefits described here: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous).
A supplement to the answer above:
import React, {useState} from "react":
import A from "...";
import B from "...";
const App = () => {
const [show, setShow] = useState(false)
return (
<div>
<A show={show} setShow={setShow} />
<B show={show} setShow={setShow} />
</div>
)
}
const A = ({show, setShow}) => (
<div>
<p>show: {show}</p>
<button onClick={() => setShow(!show)}>
toggle
</button>
</div>
)
const B = ({show, setShow}) => (
<div>
<p>show: {show}</p>
<button onClick={() => setShow(!show)}>
toggle
</button>
</div>
)

React on click event order array of data passing in the component

I'm new to React and I'd like some help please. I'm having a button and a component inside my app.js which is the main file
import React from 'react'
const App = () => {
const {data, loading, error} = useQuery(GET_DATA, {
variables: {...}
})
console.log(data)
state = {
clickSort: false
}
let clickSort = () => {
this.setState({
clickSort: true
})
}
return (
<div className="myApp">
<button onClick="{this.clickSort}">Click Me</button>
<div className="myClass">
<FooComponent fooData={data} clickSort={this.state.clickSort} />
</div>
</div>
)
}
What I want to do is when I click the button to sort the array of data I'm rendering in my component in a desc order. I was thinking of passing another parameter like a flag in the component, but I'm not sure how can I do this
If both of your components (<Button /> and <List />) are wrapped within common parent (<Parent />) you may employ the concept, known as lifting state up
Essentially, it is binding event handler within one of the child component's props (onSort() of <Button />) to the callback within parent (handleSort() of <Parent />), as well as binding dependent child prop (isSorted of <List />) to the state variable of common parent (sorted of <Parent />).
With that, you simply keep track of sorted flag within parent state (using useState() hook) and once handleSort() is triggered, it modifies that flag and consequent re-render of dependent components (<List />) takes place:
const { render } = ReactDOM,
{ useState } = React
const sampleData = ['itemC', 'itemA', 'itemD', 'itemB']
const Button = ({onSort}) => <button onClick={onSort}>Sort it</button>
const List = ({listData, isSorted}) => {
const listToRender = isSorted ? listData.sort((a,b) => b > a ? 1 : -1) : listData
return (
<ul>
{listToRender.map((li,key) => <li {...{key}}>{li}</li>)}
</ul>
)
}
const Parent = () => {
const [sorted, setSorted] = useState(false),
handleSort = () => setSorted(true)
return (
<div>
<Button onSort={handleSort} />
<List listData={sampleData} isSorted={sorted} />
</div>
)
}
render (
<Parent />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
It looks from your question that you want to let a child component (FooComponent) know that the button has been clicked so that it can process (sort) the data it has received.
There are a lot of approaches to this. For instance, you could pass a boolean property to the child component that is a flag for it to do the sorting. So the parent component tracks when the button has been clicked, and the child component just observes this (perhaps in componentDidUpdate).
This would change slightly if you are using functional components, rather than class based components, but it gives you an idea.
state = {
requestSort: false
}
requestSort = () => {
this.setState({
requestSort: true
}
}
render() {
return (
<>
<button id="myBtn" onClick={this.requestSort}>Click Me</button>
<div className="myClass">
<FooComponent requestSort={this.state.requestSort} fooData={data} />
</div>
</>
)
}
Alternatively, since the data is being passed to the child component as well, you could have the parent sort it when it is clicked. It depends on if you are doing anything else with the data (i.e. is only FooComponent the one that should have the sorted copy of the data or not).
Pass the data from the state into FooComponent and write a function that sorts the data in that state. The data will instantly be updated in the child component once the state has updated in the parent component because the child component will rerender once it's noticed that the data in the parent component doesn't match the data that it previously received. Below is an example.
import React from 'react'
const FooComponent = ({ fooData }) => (
<div>
{fooData}
</div>
)
export default class Home extends React.Component {
constructor(props){
super(props);
this.state = {
data: [1, 4, 2, 3]
}
}
sortData() {
const { data } = this.state;
this.setState({
data: data.sort((a, b) => b - a),
})
}
render(){
const { data } = this.state;
return (
<div>
<button id="myBtn" onClick={() => this.sortData()}>Click Me</button>
<div className="myClass">
<FooComponent fooData={data} />
</div>
</div>
)
}
}

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