I have a component that I can change how it is rendered based on a prop (added a failed state, and based on whether it fails or not it turns red or stays the original colour), the logic for whether failed is true or false is in the parent component.
I want to change the failed state, but only onBlur (without changing the child component). Is there a way to pass in an onBlur function which applies changes to a child prop?
Ive tried a number of different things like:
Child component
<input
failed={failed}
onBlur={onBlur}
/>
Parent component:
this.props.failed = value;
}
and in the render function:
onBlur={() => this.handleBlur(newValue)}
but it didnt work for me.
Props are data that are passed from a parent to its children and are made available through this.props in the child component.
You maintain whatever prop your are passing to child component either in parent component's state or in redux/flux state (if you have global state management).
When failed is modified, a state change should be triggered on parent component, which in-turn will trigger a re-render inside child component.
For example:
In the following, we pass failed as a prop, and onFailureUpdate function as a callback trigger to child component from parent.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
failed: false
}
}
onFailureUpdate = (value) => {
this.setState({
failed: value
});
}
render() {
return (<ChildComponent failed={this.state.failed} onFailureUpdate={this.onFailureUpdate} />)
}
}
In child component, on blur, we are using the function we passed as prop to modify state in parent, which in-turn will re-render child component.
class ChildComponent extends React.Component {
onBlur = (e) => {
this.props.onFailureUpdate(e.target.value);
}
render() {
return (
<input
value={this.props.failed}
onBlur={(e) => this.onBlur(e)}
/>
)
}
}
Other way:
Or, if there's no necessity for props or parent-child relationship, you can eliminate the need for parent container and go for state maintenance in child.
class RewrittenChildComponentWithState extends React.Component {
constructor() {
this.state = {
failed: false
};
}
onBlur = (e) => {
this.setState({
failed: e.target.value
});
}
render() {
return (
<input
value={this.state.failed}
onBlur={(e) => this.onBlur(e)}
/>
)
}
}
Hope this solves your confusion.
Related
I'm trying to learn react and ran into a snag. I'm struggling to update the parent based on the child state. I've managed to pass the child state to the parent by binding the child's state to the same child's prop when invoked by the parent.
Parent.js
import React, { Component, setState } from 'react'
import './Parent.css'
import Child from './Child'
export class Parent extends Component {
constructor(props) {
super(props)
this.state = {
childState: false
}
}
checkState(newState){
console.log(`new state is ${newState}`)
}
render() {
return (
<div class={`parent ${this.state.childState ? 'parent-child-not-clicked' : 'parent-child-clicked'}`}>
<h1>{this.state.childState === true ? 'true' : 'false'}</h1>
{/* <Child changeState={(newState)=>{newState === true ? this.setState(prevState => ({childState: prevState.childState+1})):this.setState(prevState => ({childState: prevState.childState-1}))}}></Child> */}
<Child changeState={(newState) => {console.log(newState)}}></Child>
</div>
)
}
}
export default Parent
Child.js
import React, { Component } from 'react'
import "./Child.css"
export class Child extends Component {
constructor(props) {
super(props)
this.state = {
childState: false
}
this.updateState = this.updateState.bind(this)
}
updateState(){
this.setState({
childState: !this.state.childState
}, () => {return this.state.childState})
}
render() {
return (
<div className="child">
<h1>{`child state is ${this.state.childState}`}</h1>
<div onClick={() => this.props.changeState(this.updateState())}>Click</div>
</div>
)
}
}
export default Child
The console keeps rendering undefined, meaning newState doesn't contain the boolean value true / false. Would appreciate if anyone can point me in the right direction.
Thanks in adavance
this.updateState() doesn't return anything. So nothing is sent to this.props.changeState.
Probably the simplest approach is to remove this.props.changeState from the JSX markup and move it into updateState. Then within updateState define the new state object, update the component's state with it, and pass it to the prop function. Something like this:
updateState(){
const newState = {
childState: !this.state.childState
};
this.setState(newState);
this.props.changeState(newState);
}
Then in the JSX just call updateState (putting less logic inline in the JSX and more in the functions):
<div onClick={this.updateState}>Click</div>
As an aside, while the example shown is clearly a contrived one, tracking the same state in two different places is probably the wrong design. If the parent just needs updates, pass it just the updates that it needs. But if the parent is tracking the state, the child doesn't need to duplicate that effort. You can remove state from the child entirely and just pass it the values it needs, simplifying the whole thing.
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 have a parent component which contains a function, which when called needs to acces the childrenĀ“s component state. I dont want to move the whole state to the parent component because i want the children component to be independent. What is the cleanest and most recommended way to achieve this?
class ParentComponent extends Component {
render() {
return (
<div>
<ChildComponent/>
<SaveButton onClick={this.saveFunction}/>
</div>
)
}
saveFunction = () => {
//Here i need to acces the child Component state
}
}
My solution so far was that everytime something changed in child component i called a function which was passed from the parent Component. Like this:
class ChildrenComponent extends Component {
state = {
name: "David",
age: 19
}
render() {
return (
//inputs with the inputChange function
)
}
inputChange = (e) => {
//Update the state
//Then pass the state to the parent
this.props.passStateToParent(this.state)
}
}
I would recommend to look up some of the React patterns - especially Render Props, as it allows to expose the state and wanted methods of a component - what you want in this situation.
Best of luck!
You can make a function in parent component and pass it down to child component as prop. This function could return to parent component the state of your child component. See more here: https://reactjs.org/docs/faq-functions.html
You cannot directly access the state of the child component,this can be done by passing the state to methods of parent component which are passed as props to child component,the following example demonstrate how to do it .
class ParentComponent extends React.Component {
somefunc() {
//do your action
}
render() {
<ChildComponent parentfunc={this.somefunc}/>
}
}
class ChildComponent extends React.Component {
constructor(props){
super(props)
this.state = {somedate:'value'}
this.func = this.func.bind(this)
}
func() {
this.props.parentfunc(this.state)
}
render() {
<button onClick={this.func}>text</button>
}
}
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 })
}
}
I have a react class in which I need to use shouldComponentUpdate(), to prevent an infinite loop between the component and its parent.
I simply check whether a deep clone of nextProps is equal to this.props, and I only update the component if they're not.
So far, so good. (?)
class Child extends Component {
onComponentUpdate = (e) => {
this.props.update(e)
}
shouldComponentUpdate(nextProps, nextState) {
return JSON.stringify(nextProps) !== JSON.stringify(this.props)
}
render() {
return (
<div>
// some code that might trigger onComponentUpdate()
</div>
);
}
}
Now, in my parent component, something happens that makes me want to re-render the child, without specific props changing. What I did now, is changing a counter in state and passing it to the child as a prop. I never do anything with the counter itself, it is merely an indication for the child that props actually changed so that the child should update.
class Parent extends Component {
constructor() {
super()
this.state = { counter: 0 }
}
otherChildChanged = () => {
this.setState({ counter: this.state.counter + 1 })
}
render() {
return (
<div>
<Child
counter={this.state.counter}
update={"some function"}
other={"props"}
>
</Child>
<OtherChild onChange={this.otherChildChanged}>
</OtherChild>
// some code that might trigger onComponentUpdate()
</div>
);
}
}
Is there a better way to do this?
You should pass down the size of your resizable div as a prop to the Child Component. This way, when it changes, JSON.stringify(nextProps) !== JSON.stringify(this.props) will be true and a re-render will occur.
If a component has to behave in a certain way (re-render, for example) depending on something that happens on his Parent, it should be passed to it as a prop.