Cannot change state from child to parent component - javascript

I am try to change state in parent component onChange event.
On click on Checkbox state includeExtremeClaims should be changed into true.
Parent Component:
export class ManageAnalytics extends Component {
static contextTypes = baseContextTypes
state = {
includeExtremeClaims: false
}
handleChange = (e, { name, value } = {}) => {
this.setState({ [name]: value })
}
render() {
return (
<div>
// Passing down handleChange and includeExtremeClaims state as props
<Analytics
handleChange={this.handleChange}
includeExtremeClaims={this.state.includeExtremeClaims}
/>
</div>
)
}
Child Compnent:
export class Analytics extends Component {
static contextTypes = baseContextTypes
render() {
const { handleChange, includeExtremeClaims } = this.props
return (
<Checkbox
label="Include Extreme Cases"
name="includeExtremeClaims"
onChange={handleChange}
value={includeExtremeClaims}
/>
)
}
Question is: On click on Checkbox Why my state is not changed?

Problem was in value which is provide on Checkbox, value is always the same, that is reason why is not changed:
value={includeExtremeClaims} it should be value={!includeExtremeClaims}

Related

Can we pass props from Parent to Child component in React, and set the props as state of child component?

const Parent=()=>{
return(
)
}
const Child=({data})=>{
return (
{data}
)
}
Can I set the props in Child component to its state?
Yes you can. Something like:
class Child extends Component {
constructor(props){
const {myProp} = props;
this.state = {myNumber: myProp}
render(){
const {myNumber} = this.state;
return <div>{myNumber}</div>
}
class Parent extends Component {
render () {
return <Child myProp={5} />
}
}
BUT: if your "parent" component refreshes, so does the child and the state is reverted back to the value set by the parent, and all the state changes you did on the child are lost.
Yeah here made a code sandbox example showing how to do it: https://codesandbox.io/s/stack-pass-props-fgq67n
Child component looks like this
const Input = ({ string }) => {
const [value, setValue] = useState(string);
return <input value={value} onChange={(e) => setValue(e.target.value)} />;
};
Parent Component:
export default function App() {
return (
<div className="App">
<Input string="default" />
</div>
);
}
Sometimes if the parent reloads the passed props may reset to defaults
There is a concept in React known as controlled and uncontrolled components, When your component only have props and no state inside itself then it a controlled component, that is controlled by the parent component.
Also, it is not advisable to convert the props to the state of the child component, if you want to change the value of the props, just pass an additional method as a props which will be called by the Child to update the value of the props, let show you with an example
const Parent = () => {
const [number, setNumber] = useState(0);
const updateNumberHandler = (numberToUpdate) => setNumber(numberToUpdate)
return <Child number={number} onUpdateNumber={updateNumberHandler} />
}
const Child = (props) => {
const { number, onUpdateNumber } = props;
return <button onClick={() => onUpdateNumber(number + 1)}>Updated Number: {number}</button>
}
Here you can see I am passing two props one value and one method to update that value, when the onUpdateNumber method is called the value on the parent is updated so it gets re-render and also the child gets re-render with the updated number value.

Troubles with state

I'm just started to learn react, and i have a question
Well, i can impact on state from one component to another. But can i do it in reverse?
Here's what i mean:
import React from 'react';
import Butt from './Button';
class Checkbox extends React.Component {
constructor(props) {
super();
}
render() {
return (
<div>
<Butt arg={13} />
</div>
);
}
}
export default Checkbox;
import React from 'react';
class Butt extends React.Component {
constructor(props) {
super();
this.state = {
s1: props.arg,
};
}
add = () => {
let val = this.state.s1;
val++;
this.setState({ s1: val });
};
render() {
return (
<div>
<label>
<label>
<button onClick={this.add}>add</button>
<div>{this.state.s1}</div>
</label>
</label>
</div>
);
}
}
export default Butt;
Sorry for my silly question. Thanks in advance :)
I am not sure about your question, but in react, there is a one-way flow (from parent to child) for transferring information (props, states, or ...). If you want to have access to states everywhere or set them in each direction you should use Redux or context or any other state management.
You're updating the Butt state from inside Butt so this will work fine. It won't change the value of this.props.arg though, if that's what you're asking.
Props are always non-mutable.
What you can do is have two components share the state of their parent...
class Parent extends React.Component {
state = {
val = 0
}
render () {
return (
<>
<Child1
val={this.state.val}
onChange={newVal => this.setState({ val: newVal })}
/>
<Child2
val={this.state.val}
onChange={newVal => this.setState({ val: newVal })}
/>
</>
)
}
}
Then inside the child components pass the updated value to onChange...
class Child1 extends React.Component {
handleChange() {
this.props.onChange(this.props.val + 1)
}
render() {
return (
<Button onClick={() => this.handleChange()}>
Update value
</Button>
)
}
}
This way you're just passing a new value from Child to Parent and letting Parent decide what to do with it.
Whether Child1 or Child2 sends the new value, both children will get updated when Parent calls this.setState({ val: newVal }) and changes this.state.val.

Best way to access state of a React child class component in React parent functional component (react-dual-listbox)

I tend to use react functional components and hooks as I do not have a lot of experience with react. I want to use the react-dual-listbox class component within a parent functional component. Within this parent component I want to be able to access the selected state of the child class component. What is the best way to do this?
Child react-dual-listbox component from https://github.com/jakezatecky/react-dual-listbox
import React from 'react';
import DualListBox from 'react-dual-listbox';
const options = [
{ value: 1, label: 'Option One' },
{ value: 2, label: 'Option Two' },
];
class DualListChild extends React.Component {
state = {
selected: [1],
};
onChange = (selected) => {
this.setState({ selected });
};
render() {
const { selected } = this.state;
return (
<DualListBox
options={options}
selected={selected}
onChange={this.onChange}
/>
);
}
}
Contained within a standard functional component
function Parent() {
return(
<div>
<DualListChild/>
</div>
)
}
export default Parent;
Is it possible to, for example, have a hook in the parent component that changes state corresponding to what the dual listbox has selected? Essentially I want to pass state up but to a functional component? Is there a way to do this?
Thanks
You'd do something similar to what you do in DualListChild, except using the useState hook instead:
class DualListChild extends React.Component {
onChange = (selected) => {
this.props.onSelected(selected);
};
render() {
return (
<DualListBox
options={options}
selected={this.props.selected}
onChange={this.onChange}
/>
);
}
}
function Parent() {
const [selected, setSelected] = React.useState();
return (
<div>
<DualListChild selected={selected} onSelected={setSelected} />
</div>
)
}
Now you have access to selected (and even setSelected) inside your Parent component.
As an alternative way, you can have another state that keeps track of selected options in the parent and send its setter function to the child. Whenever the state of the child is changed, call the setter function that is coming from parent. With that way, the selected options state will be up-to-date value for the child and parent components any time.
function Parent() {
const [selectedOptions, setSelectedOptions] = useState([]);
return(
<div>
<DualListChild onSelectedOptionsChange={setSelectedOptions}/>
</div>
)
}
export default Parent;
class DualListChild extends React.Component {
...
onChange = (selected) => {
this.setState({ selected });
props.onSelectedOptionsChange(selected);
};
...
}

React Component not updating with state change

I currently have a reducer that does a deep copy of state and returns it with the updated value.
function countableItems(state = initialState, action) {
switch (action.type) {
case types.ADD_TO_SUM:
let denomMap = findDenomination(state.denomGroups, action),
nestedCopy = Immutable.fromJS(state);
return nestedCopy.setIn(['denomGroups', denomMap.group, denomMap.key, denomMap.index, 'sum'], parseFloat(action.value)).toJS();
default:
return state;
}
}
In my render function of the display Component I see the correct updated values in this.props.denoms The render() function builds up child <DenomInput> components, and when I set my breakpoints I see the correct data being passed in
render() {
let denomGroups = this.props.denoms.map((denom, i) => {
return (
Object.keys(denom).map((key) => {
let denoms = denom[key].map((item, i) => {
return <DenomInput denom={item} onDenomChange={this.onDenomChange} key={i}></DenomInput>
});
return (<div className="col"><h2>{key}</h2>{denoms}</div>)
})
);
});
return (
<div className="countable-item-wrapper">
<div className="row">
{denomGroups}
</div>
</div>
);
}
However when the <DenomInput> components render it renders the same value as what they were initially set
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class DenomInput extends Component {
constructor(props) {
super(props);
this.state = { denom: props.denom }
this.handleKeyUp = this.handleKeyUp.bind(this);
}
handleKeyUp = (e) => {
this.props.onDenomChange(e.target.value, this.state.denom.name);
}
render() {
return (
<div className="input-group denom">
<span className="input-group-addon">{this.state.denom.label}</span>
<input
type="text"
className="form-control"
onChange={this.handleKeyUp}
value={this.state.denom.sum} />
<span className="input-group-addon">{this.state.denom.count | 0}</span>
</div>
);
}
}
DenomInput.PropTypes = {
denom: PropTypes.object.isRequired,
onDenomChange: PropTypes.function
}
export default DenomInput;
What piece am I missing to update the view with React and Redux?
May be componentWillReceiveProps can do the trick. It will update the state of the component whenever new data is receive from parent, and call the render function again.
Try
class DenomInput extends Component {
...
componentWillReceiveProps(nextProps) {
this.setState({ denom: nextProps.denom })
}
...
}
It looks like you're seeding your initial state with the props from your store. You then render from the component state, but you never update the component state. They only get set once because constructor is only called once the component is rendered. To fix, either remove this component state entirely and just connect it to the redux store, or update the component state onChange. I recommend removing the local state. I have found that keeping the two states in sync is error-prone.
constructor(props) {
super(props);
this.state = { denom: props.denom }
this.handleKeyUp = this.handleKeyUp.bind(this);
}
handleKeyUp = (e) => {
this.props.onDenomChange(e.target.value, this.state.denom.name);
this.setState({ denom: /*new state identitcal to change in redux store*/ })
}
edit2: An example of raising state up. The steps are:
1. Connect one of your parent components and grab the appropriate slice of state with a mapStateToProps function.
2. Pass the props through your connected parent component to DenomInput.
4. In this.denomsChange, dispatch the appropriate action. It is unclear what this is since you did not include your action in the post.
class DenomInput extends Component {
...
render() {
return (
<div className="input-group denom">
<span className="input-group-addon">{this.props.denom.label}</span>
<input
type="text"
className="form-control"
onChange={this.handleKeyUp}
value={this.props.denom.sum} />
<span className="input-group-addon">{this.props.denom.count | 0}</span>
</div>
);
}
}
export default DenomInput;

React - Can A Child Component Send Value Back To Parent Form

The InputField & Button are custom components that go into a form to create a form. My issue is how do I send the data back up to form so that on button click, I can fire ajax on the form with data (username & password):
export default auth.authApi(
class SignUpViaEmail extends Component{
constructor(props){
super(props);
this.state = {
email : "",
password : ""
};
this.storeEmail = this.storeEmail.bind( this );
this.storePassword = this.storePassword.bind( this );
}
storeEmail(e){
this.setState({ email : e.target.value });
}
storePassword(e){
this.setState({ password : e.target.value });
}
handleSignUp(){
this.props.handleSignUp(this.state);
}
render(){
return(
<div className="pageContainer">
<form action="" method="post">
<InputField labelClass = "label"
labelText = "Username"
inputId = "signUp_username"
inputType = "email"
inputPlaceholder = "registered email"
inputClass = "input" />
<Button btnClass = "btnClass"
btnLabel = "Submit"
onClickEvent = { handleSignUp } />
</form>
</div>
);
}
}
);
Or Is it not recommended & I should not create custom child components within the form?
child component => InputField
import React,
{ Component } from "react";
export class InputField extends Component{
constructor( props ){
super( props );
this.state = {
value : ""
};
this.onUserInput = this.onUserInput.bind( this );
}
onUserInput( e ){
this.setState({ value : e.target.value });
this.props.storeInParentState({[ this.props.inputType ] : e.target.value });
}
render(){
return <div className = "">
<label htmlFor = {this.props.inputId}
className = {this.props.labelClass}>
{this.props.labelText}
</label>
<input id = {this.props.inputId}
type = {this.props.inputType}
onChange = {this.onUserInput} />
<span className = {this.props.validationClass}>
{ this.props.validationNotice }
</span>
</div>;
}
}
Error : I get the error e.target is undefined on the parent storeEmail func.
React's one-way data-binding model means that child components cannot send back values to parent components unless explicitly allowed to do so. The React way of doing this is to pass down a callback to the child component (see Facebook's "Forms" guide).
class Parent extends Component {
constructor() {
this.state = {
value: ''
};
}
//...
handleChangeValue = event => this.setState({value: event.target.value});
//...
render() {
return (
<Child
value={this.state.value}
onChangeValue={this.handleChangeValue}
/>
);
}
}
class Child extends Component {
//...
render() {
return (
<input
type="text"
value={this.props.value}
onChange={this.props.onChangeValue}
/>
);
}
}
Take note that the parent component handles the state, while the child component only handles displaying. Facebook's "Lifting State Up" guide is a good resource for learning how to do this.
This way, all data lives within the parent component (in state), and child components are only given a way to update that data (callbacks passed down as props). Now your problem is resolved: your parent component has access to all the data it needs (since the data is stored in state), but your child components are in charge of binding the data to their own individual elements, such as <input> tags.
Addendum
In response to this comment:
What if we render a list of the child component? Using this single source of truth in Lifting state up technique will let the parent controls all the state of all the child inputs right? So how can we access each of the value input in the child component to (which is rendered as list) from the parent component?
For this case, you may map a child component for each element in the list. For example:
class Parent extends Component {
//...
handleChangeListValue = index => event => {
this.setState({
list: this.state.list
.map((element, i) => i === index ? event.target.value : element)
});
}
//...
render() {
return this.state.list.map((element, i) => (
<Child
value={element}
onChangeValue={this.handleChangeListValue(i)}
/>
));
P.S. Disclaimer: above code examples are only for illustrative purposes of the concept in question (Lifting State Up), and reflect the state of React code at the time of answering. Other questions about the code such as immutable vs mutable array updates, static vs dynamically generated functions, stateful vs pure components, and class-based vs hooks-based stateful components are better off asked as a separate question altogether.
React class component
Parent.js
import React, { Component } from 'react';
import Child from './child'
class Parent extends Component {
state = {
value: ''
}
onChangeValueHandler = (val) => {
this.setState({ value: val.target.value })
}
render() {
const { value } = this.state;
return (
<div>
<p> the value is : {value} </p>
<Child value={value} onChangeValue={this.onChangeValueHandler} />
</div>
);
}
}
export default Parent;
Child.js
import React, { Component } from 'react';
class Child extends Component {
render() {
const { value , onChangeValue } = this.props;
return (
<div>
<input type="text" value={value} onChange={onChangeValue}/>
</div>
);
}
}
export default Child;
React hooks
Parent.js
import { useState } from "react";
import Child from "./child";
export default function Parent() {
const [value, changeValue] = useState("");
return (
<div>
<h1>{value}</h1>
<Child inputValue={value} onInputValueChange={changeValue} />
</div>
);
}
Child.js
export default function Child(props) {
return (
<div>
<input
type="text"
value={props.inputValue}
onChange={(e) => props.onInputValueChange(e.target.value)}/>
</div>
);
}
Parent.js
import SearchBar from "./components/SearchBar";
function App() {
const handleSubmit = (term) => {
//Log user input
console.log(term);
};
return (
<div>
<SearchBar onPressingEnter={handleSubmit} />
</div>
);
}
export default App;
Child.js
import { useState } from "react";
function SearchBar({ onPressingEnter }) {
const [UserSearch, setname] = useState("[]");
/* The handleChange() function to set a new state for input */
const handleChange = (e) => {
setname(e.target.value);
};
const onHandleSubmit = (event) => {
//prevent form from making a http request
event.preventDefault();
onPressingEnter(UserSearch);
};
return (
<div>
<form onSubmit={onHandleSubmit}>
<input
type="search"
id="mySearch"
value={UserSearch}
onChange={handleChange}
name="q"
placeholder="Search the siteā€¦"
required
/>
</form>
</div>
);
}
export default SearchBar;
You can add a "ref name" in your InputField so you can call some function from it, like:
<InputField
ref="userInput"
labelClass = "label"
labelText = "Username"
inputId = "signUp_username"
inputType = "email"
inputPlaceholder = "registered email"
inputClass = "input" />
So you can access it using refs:
this.refs.userInput.getUsernamePassword();
Where getUsernamePassword function would be inside the InputField component, and with the return you can set the state and call your props.handleSignUp

Categories

Resources