I have a form that has a submit button.
That form calls a function onclick that sets the state of something from false to true.
I then want to pass this state back to the parent so that if it is true it renders componentA but if it is false it renders componentB.
How would I do that in react?
I know I need to use state or props but not sure how to do it. also is this contradicting the one-way flow react principle??
ComponentA code:
<form onSubmit={this.handleClick}>
handleClick(event) {
this.setState({ decisionPage: true });
event.preventDefault();
};
Parent component that controls what it displays:
return (
<div>
{this.props.decisionPage ?
<div>
<LoginPage />
</div>
:
<div>
<Decision showThanks={this.props.showThanks}/>
</div>
}
</div>
)
Move handleClick to the parent and pass it to the child component as a prop.
<LoginPage handleClick={this.handleClick.bind(this)}/>
Now in the child component:
<form onSubmit={this.props.handleClick}>
This way submitting the form will update the state in parent component directly. This assumes you don't need to access updated state value in child component. If you do, then you can pass the state value back from the parent to the child as a prop. One-way data flow is maintained.
<LoginPage handleClick={this.handleClick.bind(this)} decisionPage={this.state.decisionPage}/>
Pass State as a Prop
I have recently learned a method that works great for changing state in a <Parent /> component from a <Child /> component.
This might not be the exact answer for this question, but it is surely applicable to this situation and other similar situations.
It works like this:
set the default STATE in the <Parent /> component - Then add the 'setState' attribute to the <Child />
const Parent = () => {
const [value, setValue] = useState(" Default Value ");
return (
<Child setValue={setValue} />
)
}
Then change the state(in Parent) from the Child component
const Child = props => {
return (
<button onClick={() => props.setValue(" My NEW Value ")}>
Click to change the state
</button>
)
}
When you click the button, the state in the <Parent /> component will change to whatever you set the state to in the <Child /> component, making use of "props".. This can be anything you want.
I Hope this helps you and other devs in the future.
In Parent Component:
getDatafromChild(val){
console.log(val);
}
render(){
return(<Child sendData={this.getDatafromChild}/>);
}
In Child Component:
callBackMethod(){
this.props.sendData(value);
}
Simple Steps:
Create a component called Parent.
In Parent Component create a method that accepts some data and sets
the accepted data as the parent's state.
Create a component called Child.
Pass the method created in Parent to child as props.
Accept the props in parent using this.props followed by method
name and pass child's state to it as argument.
The method will replace the parent's state with the child's state.
Here is an example of how we can pass data from child to parent (I had the same issue and use come out with this )
On parent, I have a function (which I will call from a child with some data for it)
handleEdit(event, id){ //Fuction
event.preventDefault();
this.setState({ displayModal: true , responseMessage:'', resId:id, mode:'edit'});
}
dishData = <DishListHtml list={products} onDelete={this.handleDelete} onEdit={(event, id) => this.handleEdit(event, id)}/>;
At the child component :
<div to="#editItemDetails" data-toggle="modal" onClick={(event)=>this.props.onEdit(event, listElement.id) }
className="btn btn-success">
In React you can pass data from parent to child using props. But you need a different mechanism to pass data from child to parent.
Another method to do this is to create a callback method. You pass the callback method to the child when it's created.
class Parent extends React.Component {
myCallback = (dataFromChild) => {
//use dataFromChild
},
render() {
return (
<div>
<ComponentA callbackFromParent={this.myCallback}/>
</div>
);
}
}
You pass the decisionPage value from the child to the parent via the callback method the parent passed.
class ComponentA extends React.Component{
someFn = () => {
this.props.callbackFromParent(decisionPage);
},
render() {
[...]
}
};
SomeFn could be your handleClick method.
if your parent component is a functional component you can now use the use context way. Which involves passing the ref to the object and the ref to the stateChanging method. What this will allow you to do is change state from parrent in child and also ref tht state while remaining synced with Parent State. You can learn more about this in a youtubeVideo by codedamn titled 'React 16.12 Tutorial 20: Intro to Context API' and 'React 16.12 Tutorial 21: useContext'
This works exactly what I wanted. But in case of set of data with say 50 records with (customer_id, customer_name) as values to be updated from child to parent, then this lags. Do the setState using React.useEffect in child component
i have same problem and so performed this code :
in Parent
const PARENT = () => {
const [value, setValue] = useState("....");
return (
)
}
in Child
const CHILD = props => {
return (
<button onClick={() => props.setValue("....")}>
Click to change the state
</button>
)
}
Related
I am dealing with two components and one store.Components are Child and Parent,Store is store. Parent when rendering, make the child component up and parent listens to store.Now I want to update the state of variable in Store, by exposing a method from Store. The parent pass this method as a call back to child. Child has a dialog box, and if user closes/dismiss that dialog box, the clearStoreInfo() should be called, which is passed by parent to child. But when i do so, I get error
React cannot update during an existing state transition (such as within render ) functional component
Store looks as :
class Stores {
........
........
........
#action.bound
clearStoreInfo = () => {
console.log(" clear info");
}
}
Parent Component:
import Store ........
class InfoContainer extends React.Component {
return (
<div id={"info"} className={"container"}>
<ButtonPanel store={Store} />
</div>
}
const ButtonPanel = (props) => {
return (
.....
.....
<div>
<ChildComponent clearStoreInfo={props.store.clearStoreInfo}/>
</div>
......
}
class ChildComponent extends React.Component {
render(){
const {clearStoreInfo} = this.props;
return (
////if -else ladder
clearStoreInfo(); // warning line.
<Dialog.......
onClose={clearStoreInfo}
/>
)
}
//Because of warning, the dialog box dont come. If i remove clearStoreInfo(), then dialog box works fine.
Is there any easy workaround given these components and store?
The wiring works fine, because I can see console log,based on if-else ladder, but its just the warning is messing things up internally.onClose is able to call the clearStoreInfo perfectally, but its when I manually call it, I am getting a warning.
Let's say I have a parent component in React with 3 separate child components of the same component class (meaning, within class Parent I have 3 Child components). How do I access each child's state within the Parent component?
My initial thoughts are to have a separate variable for each Child's state that I want to access (I only want to access the filled variable for each child). But I feel that this is certainly a sloppy solution to something that is already in place with React, so would appreciate any pointers.
Example code below for illustration purposes.
const Parent = (props) => {
return (
<div>
<Child/>
<Child/>
<Child/>
</div>
);
}
const Child = (props) => {
const [filled, setFilled] = useState(false);
return (
<div></div>
);
}
Perhaps the better question is how do I access the particular child? And once accessed, how do I access its filled state (callback function)? I've read about useRef, is that where I should be looking here?
If what you are trying to do is report back to the parent the childs's state, you can do that by passing down from the parent, via props, a function to report that state back, as such:
const Parent = (props) => {
const reportChildState = (value) =>{
//do something with the child filled state
}
return (
<div>
<Child reportState={reportChildState}/>
<Child reportState={reportChildState}/>
<Child reportState={reportChildState}/>
</div>
);
}
const Child = (props) => {
//in here you can call props.reportChildState(filled)
const [filled, setFilled] = useState(false);
return (
<div></div>
);
}
As far as I'm aware there isnt a way to access a child components state from the parent. The only solutions are to either pass the state object into the child as a prop, using the context API or using a thirst party state management such as redux.
I wouldnt use useref for accessing a child's state.
You actually wouldn't directly access the children to retrieve their states. What you want here is a Context that encompases the parent component. Check out the React Context API. In short, you can create a "context" that contains states that need to be shared between multiple components. Once the context is made, a Provider is also created with that context. This provider is a component that accepts a value prop. This prop contains an object of all the state values and setter functions within the context. Child components of a Provider component can use the useContext hook to retrieve the values and functions from the value prop of the Provider.
Code example:
MyContext.js
import React, {createContext, useState} from 'react';
// Create the context and give it default values
export const MyContext = createContext(defaultValuesObject);
// We create a component that wraps around the provider, and is stateful. The states and their setters are placed into the provider, which is then returned.
const MyProvider = (props) => {
const [firstName, setFirstName] = useState("")
const [lastName, setLastName] = useState("")
const dataToShare = {
firstName,
setFirstName,
lastName,
setLastName,
}
// Return the context provider with the data already inside, and fill the children.
return (
<MyContext.Provider value={dataToShare}>
{props.children}
</MyContext.Provider>
)
}
We have the provider now. In your parent component's code, use the useContext hook to give the component access to the values and functions stored inside the provider component.
MyParentComponent.jsx
import React, {useContext} from 'react';
import MyProvider, { MyContext } from 'MyContext'
const MyComponent = (props) => {
// useContext returns the value stored in the provider so we can use it and the functions inside. The context is maintained inside the states in the provider.
const providerValue = useContext(MyContext)
// OR
const { firstName, setFirstName, lastName, setLastName } = useContext(MyContext)
return (
<div>
// Provide the first child component with the values and functions from the context
<MyChildComponentOne someProp={providerValue} />
// Provide the second child component with the values and functions from the context
<MyChildComponentTwo someProp={providerValue} />
// Provide the second third component with the values and functions from the context
<MyChildComponentThree someProp={providerValue} />
<div/>
)
}
Now, we still won't be able to use the context without a provider, which MUST wrap around the component(s) calling useContext for that specific context. Assuming the ParentComponent is used inside of App.jsx:
App.jsx
...imports and whatever other code you have in here
/// The jsx for the App component or whatever component calls MyParentComponent
return <div>
<MyProvider>
<MyParentComponent>
</MyProvider>
</div>
To re-iterate, you are taking the state OUT of the child/parent components, and putting them INTO the Provider created by the Context. Child components of the Provider can call useContext and gain access to the data and functions in the Provider's value prop.
There is no direct way to pass information from the child to the parent, only the other way around.
But that means you can also pass functions from the parent to the child! One common pattern for achieving what you need would be to pass the state set function to the child, so it can alter the parent's state. Like so:
const Parent = (props) => {
const [childStates, setChildStates] = useState({ child1: '', child2: '', child3: '' })
return (
<div>
<Child
state={childStates.child1}
setState={(val) => setChildStates((prev) => ({ ...prev, child1: val }))}
/>
<Child
state={childStates.child2}
setState={(val) => setChildStates((prev) => ({ ...prev, child2: val }))}
/>
<Child
state={childStates.child3}
setState={(val) => setChildStates((prev) => ({...prev, child3: val }))}
/>
</div>
);
}
I have an array which I want to save in my database. I have a page (parent component) and a form (child component) where my birthday input is (the one I'm saving in database). The select html elements are in the child component, and I take their values after every change. Now I need to pass recieved values from select elements back to my parent component and update the array with the recieved props. I will try to recreate my code as best as I can:
AuthenticationPage.js (Parent):
import React from 'react';
class AuthenticationPage extends Component {
constructor(props) {
super(props);
this.state({
setMonth:null
setDay:null
setYear:null
})
}
render() {
return(
<div>
<SignupForm // This is where I call my child component
onChange={(monthValue) => this.setState({ setMonth: monthValue })}
initialValues={{
dateofbirth: [
{
month: this.state.setMonth, // This one is okey but I can use onChange just to change one state
day: this.state.setDay,
year: this.state.setYear
}
]
}}
/>
</div>
)
}
}
export default AuthenticationPage;
SignupForm.js (Child):
import React from "react";
import SelectSearch from "react-select-search";
const SignupForm = (props) => (
<FinalForm
{...props}
render={(fieldRenderProps) => {
const {
// Here I render props from parent component
} = fieldRenderProps;
function monthPicker(monthValue) {
props.onChange(monthValue);
// How can I update the state of setDay and setYear states in parent component
}
return (
<Form className={classes} onSubmit={handleSubmit}>
<SelectSearch
options={month}
onChange={(monthValue) => monthPicker(monthValue)} // This is ok, I change setMonth state in parent with this function
/>
<SelectSearch
options={day}
// How to work with this, this is day input
/>
<SelectSearch
options={year}
// How to work with this, this is year input
/>
</Form>
);
}}
/>
);
export default SignupForm;
So basically I want to update states in parent component after onChange happens on select elements in my child component. I'm new to React and I can't figure this out whole day, so any help will mean a lot.
Child should receive a 'onChange' function prop. That will be called inside the child component, every time the values on the form are changed (this.props.onChange(newValue)).
The parent should hold a state of the values that will be updated accordingly (<SignupForm ... onChange={(newValue) => this.setState({ value: newValue })} />)
From parent to child you can pass data through props, but from child to parent best way is by function , i ll try to write an example below, i always code with functional component so my syntax won't be right below, but i hope you ll get the idea ...
Parent Component
class Parent extends React.Component {
constructor(props) {
super(props);
this.state({
monthValue:null
})
}
// this function send as a prop
const updateMonthValue =(value)=>{
this.state.monthValue=value
}
render() {
return <Child updateMonthValue={updateMonthValue} />;
}
}
Child Component
const Child =(props) => {
const submitHandler =(value) =>{
//here you can call the function of parent and the function in the parent will update state of parent
props.updateMonthValue(value)
}
render() {
return <h1><button onClick={()=>submitHandler("june")} /></h1>;
}
}
I'd like to know, how to handle the PropTypes Error when passing a component as a child:
Failed prop type: The prop `value` is marked as required in `ChildComponent`, but its value is `undefined`.
The render works as expected and it's passing the value prop correctly.
I suppose this happens because I am putting the component in the App component's render function without any props.
I am only passing those props to the ChildComponent when the ParentComponent maps over its children (which is the ChildComponent).
See the code: https://codesandbox.io/embed/r70r5z3j9q
Is there a way to prevent this from happening?
How should I be structuring my components?
Am I not supposed to passed components as children?
EDITED: Changed prop "name" to "value". To give it a more generic feel.
I tried to simplify the problem in the code.
I know I could pass the prop directly in App.
The use case would be when the parent is doing calculations and those calculations are supposed to be passed to the child. Without explicitly knowing what these children are.
That's why I'm using it as child in the first place.
You're using cloneElement and you're passing prop to it, not to original element. To fix it, pass props directly:
const App = () => (
<div>
<ParentComponent>
<ChildComponent name="bob" />
</ParentComponent>
</div>
);
You could easily pass component as a prop (not children) to you ParentComponent and render it only after it takes some heavy calculations:
const App = () => (
<div>
<ParentComponent component={ChildrenComponent} />
</div>
);
const ParentComponent extends React.Component {
state = { heavyComputationFinished: false } // initial state
componentDidMount() {
runYourHeavyComputations
.then(() => { this.setState({ heavyComputationsFinished: true }) })
}
render() {
const { component } = this.props
const { heavyComputationsFinished, name } = this.state
// return nothing if heavy computations hasn't been finished
if (!heavyComputationsFinished) { return null }
// we're getting this component (not its rendering call) as a prop
return React.render(component, { name })
}
}
Its possible to transfer component in props with children method?
I have to components:
let a = (<div>
<button onClick={TContainer.METHOD}>TuCLIK</button>
</div>);
<TContainer data={ restaurantList } component={a}/>
I want to call method in childen but create element in parent. I want to pass this component on props.
If its possible i dont know what writing in TContainer.METHOD to call childen method
You are not passing a component in your props, it's an expression.
A component should be either a class the extends React.Component or a function that returns a jsx markup.
Now when we know that components are just functions, we know that we can pass parameters to them, hence we can pass a function reference as a parameter:
let A = (onClick) => <div><button onClick={onClick}>TuCLIK</button></div>;
<TContainer data={ restaurantList } component={<A onClick={TContainer.METHOD} />}/>
Note that components should be capitalized.
Edit
As a followup to your comment, sorry but i misunderstood your question i guess.
You can't pass a reference of a method from a React component like that.
We can use couple of approaches regarding this scenario, one of them
is to use this.props.children and pass the child component as a
child.
For example - <Parant><Child/></Parent>
We can pass the child component as a prop.
For example - <Parent component={Child} /> or <Parent component={<Child />} />
We can write the parent component as a HOC and wrap the child
with it.
For example - Parent(Child)
In all the above examples you can't pass directly a reference of a function that is declared inside the parent's scope (as a prop to the child).
In order to pass the child a prop within the parent's internal scope you should do it inside the render method.
For example:
render() {
return (
<div>
<this.props.component onClick={this.handleClick}/>
</div>
);
}
This is a snippet that demonstrate one of the examples above:
const Child = ({onClick}) => <div onClick={onClick}>Im a child, Click me!</div>
class Parent extends React.Component {
constructor(props){
super(props);
this.state = {
counter: 0
}
this.addCount = this.addCount.bind(this);
}
addCount(){
this.setState({counter: this.state.counter + 1});
}
render() {
return (
<div>
<div>{`Count = ${this.state.counter}`}</div>
<this.props.component onClick={this.addCount}/>
</div>
);
}
}
const App = () => <Parent component={Child} />;
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>