This is weird, simple checkbox component state changes, prop does not and UI does not update!
import React, { Component } from 'react';
import { Checkbox } from 'semantic-ui-react'
export default class UiCheckBox extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
label: '',
checked: false
};
}
render() {
return (
<Checkbox label={this.props.label} name={this.props.name} checked={this.props.checked} onChange={this.handleChange.bind(this)} />
);
}
handleChange() {
this.setState({
checked: !this.state.checked
});
console.log("prop:" + this.props.checked);
console.log("state:" + !this.state.checked);
}
}
If i change
checked={this.props.checked}
To this
checked={this.state.checked}
It works, but I cant set the initial value of the checkbox, what am I doing wrong, PS i'm certain this was working earlier[honest] ?
This is how I'm using it.
<UiCheckBox name={"Tea"} label={"Tea"} checked={false} />
Idea's anyone ?
Thanks
Your handleChange() only changes this.state.checked. this.state.checked is not used in your render() method. Therefore, no visible change occurs.
If you want to change props: you'll have to pass a function that updates the original data store.
Else: you can set default state using props.
See below for a practical example 👇
// Check Box.
class CheckBox extends React.Component {
// State.
state = {checked: this.props.checked}
// Render.
render() {
const {checked} = this.state
return (
<React.Fragment>
<label>{`${checked}`}</label>
<input type="checkbox" checked={checked} onChange={this.toggle}/>
</React.Fragment>
)
}
// Toggle.
toggle = event => this.setState(state => ({checked: !state.checked}))
}
// Mount.
ReactDOM.render(<CheckBox checked={true}/>, document.querySelector('#root'))
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Related
I have a React file which displays a list of city data as a component. there is an input textbox above it which needs to accept user input. i am using state to display an initial string in the textbox, but i cannot get onChange to successfully use a function to setState. troubleshooting it with console.log i can see that when i attempt to change the state the function i am pointing to with onChange does work and changes one letter, but then the state snaps back to its default value. the problem seems to be with setState not saving the change and reverting back to the initial state after any changes are made. the text box content appears to not change at all, thought console.log shows a one letter change but then reverts back to the original state.
how do i update state? i want the user to be able to punch a number in and then compare it with the list.
import React, {Component} from 'react';
import Table from './Table';
import cities from './Cities';
class App extends Component {
state = {
userInput: "Your City Population"
}
popChanger = (event) => {
this.setState( {userInput: event.target.value} );
//console.log(event.target.value);
}
yourCity = (
<div>
<input
type='text'
onChange={this.popChanger}
value={this.state.userInput}
/>
</div>
)
render() {
return (
<div className = "App">
{this.yourCity}
<Table characterData = {cities} />
</div>
);
}
}
export default App;
setState() is saving your changes, just not in the right place,
popChanger() is an arrow function and updates the state of the App component,
yourCity has it's own this so it doesn't know about the App state.
you can either cahnge yourCity to an arrow function that returns the html you want like
class TodoApp extends React.Component {
state = {
a: ''
};
YourCity = () => (
<div>
<input type="text" onChange={this.handleChange} value={this.state.a} />
</div>
}
handleChange = e => this.setState({a : e.target.value})
render() {
return (
<div>
<this.YourCity />
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
Or, create yourCity component outside and pass the handleChange as a prop :
const YourCity = props => (
<div>
<input type="text" onChange={props.handleChange} value={props.value} />
</div>
)
class TodoApp extends React.Component {
state = {
a: ''
};
handleChange = e => this.setState({a : e.target.value})
render() {
return (
<div>
<YourCity handleChange={this.handleChange} value={this.state.a}/>
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
The state is updating but you can't see that because this.yourCity doesn't re-render
popChanger = (event) => {
this.setState( {userInput: event.target.value} );
console.log(event.target.value);
}
yourCity(){
return <div>
<input
type='text'
onChange={this.popChanger}
value={this.state.userInput}
/>
</div>
}
render() {
return (
<div className = "App">
{this.yourCity()}
</div>
);
}
}
OK so I have an input field that whose value is pre-loaded when the component mounts (this.state.color) and I'm attempting to add a handleColorPicker() function either onClick or onFocus that will dropdown a color picker from https://casesandberg.github.io/react-color/. I'll paste the relevant code below:
import React, { Component } from 'react';
import { ChromePicker } from 'react-color';
class App extends Component {
constructor(props) {
super(props);
this.state = {
color: 'FFFFFF',
};
this.handleChange = this.handleChange.bind(this);
this.handleColorPicker = this.handleColorPicker.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleColorPicker(){
console.log('open');
return(
<ChromePicker />
)
}
render() {
return(
<input
className="App-textForm"
type="text"
name="color"
value={this.state.color}
onChange={this.handleChange}
onClick={this.handleColorPicker}
/>
);
}
}
As constructed, it console.logs 'open' every time I click on it.
Is there anything obvious I'm missing as to why that onClick wouldn't trigger the ChromePicker? I've tried changing onClick to onFocus and have tried wrapping my input in a div with an onClick={this.handleColorPicker}. Any help would be appreciated, thanks!
onClick event listener doesn't do anything with the returned component. You need to set a state the renders the component conditionally like
import React, { Component } from 'react';
import { ChromePicker } from 'react-color';
class App extends Component {
constructor(props) {
super(props);
this.state = {
color: 'FFFFFF',
isColorPickerOpen: false
};
this.handleChange = this.handleChange.bind(this);
this.handleColorPicker = this.handleColorPicker.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleColorPicker(){
console.log('open');
this.setState({ isColorPickerOpen: true });
}
render() {
return(
<React.Fragment>
<input
className="App-textForm"
type="text"
name="color"
value={this.state.color}
onChange={this.handleChange}
onClick={this.handleColorPicker}
/>
{isColorPickerOpen? <ChromePicker /> : null}
</React.Fragment>
);
}
}
The problem is that you are not rendering the picker, you are just returning it and then doing nothing with it.
What you need to do is render the picker, you can do that by using the state and hide/show the picker based on the user selection. For example:
state = {
showPicker: false,
};
handleColorPicker(){
console.log('open');
this.setState(current => ({
showPicker: !current.showPicker, // <-- Toggle the state
}));
}
render() {
const { showPicker } = this.state;
return (
<div>
<input
className="App-textForm"
type="text"
name="color"
value={this.state.color}
onChange={this.handleChange}
onFocus={this.handleColorPicker} // <--- Open the picker on focus
onBlur={this.handleColorPicker} // <--- Hide it on blur? You need to define when to hide it
/>
{ showPicker && <ChromePicker /> }
</div>
);
}
using onFocus and onBlur the state change and the picker gets renderer or not, based on the value of showPicker.
You need to define when to hide it, onBlur might not be what you want.
You are attaching your handleColorPicker to run correctly, but you shouldn't be returning the ChromePicker in that function.
Take a look at this CodeSandbox Example.
Notice how I have state in my component (isColorPickerOpen) that keeps track of whether the color picker is showing or not. My click handler toggles this state between true and false.
Then in my render method, I only render the ChromePicker component when isColorPickerOpen is true.
OK, so you are not rendering the <ChromePicker />
try this
class App extends Component {
constructor(props) {
super(props);
this.state = {
color: 'FFFFFF',
isPickerActive: false
};
this.handleChange = this.handleChange.bind(this);
this.handleColorPicker = this.handleColorPicker.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleColorPicker(){
this.setState({isPickerActive: true});
}
render() {
return(
<div>
<input
className="App-textForm"
type="text"
name="color"
value={this.state.color}
onChange={this.handleChange}
onClick={this.handleColorPicker}
/>
{this.state.isPickerActive && <ChromePicker />}
<div>
);
}
}
But it will just open the picker. Hope it will help.
With the onClick you are not render ChromePicker when it return.
Instead you can have an state to handle the ChromePicker render. Every time that you click or focus on you input, you can change the state, and then the component will be re render again.
Example:
import React, { Component } from 'react';
import { ChromePicker } from 'react-color';
class App extends Component {
constructor(props) {
super(props);
this.state = {
color: 'FFFFFF',
showChromePicker: false,
};
this.handleChange = this.handleChange.bind(this);
this.handleColorPicker = this.handleColorPicker.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleColorPicker(){
console.log('open');
this.setState({
showChromePicker: true,
});
}
render() {
const { showChromePicker } = this.state;
return(
<div>
<input
className="App-textForm"
type="text"
name="color"
value={this.state.color}
onChange={this.handleChange}
onClick={this.handleColorPicker}
/>
{showChromePicker ? <ChromePicker /> : null}
</div>
);
}
}
I'm having some problems when I try to update all childs states from one of the child, here is an example of my code. The idea is to autoupdate all components from one of them.
I'm new in react, I have only been using for a week, so probably all this is a misunderstanding.
https://codesandbox.io/s/430qwoo94
import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
filedStr: 'some text',
fieldObj: {
field1: true,
field2: true
}
}
}
updObj = (which, val) => {
this.setState(prevState => ({
fieldObj: {
...prevState.fieldObj,
[which]: val,
},
}));
};
render() {
return (
<div>
<h2>Parent</h2>
Value in Parent Component State: {this.state.fieldObj.field1 ? 1 : 0} : {this.state.fieldObj.field2 ? 1 : 0}
<br />
<Child obj={this.state.fieldObj} onUpdate={this.updObj} />
<br />
<Child obj={this.state.fieldObj} onUpdate={this.updObj} />
<br />
<Child obj={this.state.fieldObj} onUpdate={this.updObj} />
</div>
)
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
obj: props.obj
}
}
update = (which) => {
this.props.onUpdate(which, !this.state.obj[which]);
this.setState(prevState => ({
obj: {
...prevState.obj,
[which]: !prevState.obj[which],
},
}));
};
render() {
return (
<div>
<h4>Child</h4>
Value in Child State: {this.state.obj.field1 ? 1 : 0} : {this.state.obj.field2 ? 1 : 0}<br />
<button type="button" onClick={(e) => { this.update('field1') }}>field1</button>
<button type="button" onClick={(e) => { this.update('field2') }}>field2</button>
</div>
)
}
}
render(<Parent />, document.getElementById('root'));
When all child components values are directly derivable from the props you do not need to create a state in child which is a replica of props and maintain it, what you need to do is modify the parent's state directly like
import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
filedStr: 'some text',
fieldObj: {
field1: true,
field2: true
}
}
}
updObj = (which, val) => {
this.setState(prevState => ({
fieldObj: {
...prevState.fieldObj,
[which]: val,
},
}));
};
render() {
return (
<div>
<h2>Parent</h2>
Value in Parent Component State: {this.state.fieldObj.field1 ? 1 : 0} : {this.state.fieldObj.field2 ? 1 : 0}
<br />
<Child obj={this.state.fieldObj} onUpdate={this.updObj} />
<br />
<Child obj={this.state.fieldObj} onUpdate={this.updObj} />
<br />
<Child obj={this.state.fieldObj} onUpdate={this.updObj} />
</div>
)
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
obj: props.obj
}
}
update = (which) => {
this.props.onUpdate(which, !this.props.obj[which]);
};
render() {
return (
<div>
<h4>Child</h4>
Value in Child State: {this.props.obj.field1 ? 1 : 0} : {this.props.obj.field2 ? 1 : 0}<br />
<button type="button" onClick={(e) => { this.update('field1') }}>field1</button>
<button type="button" onClick={(e) => { this.update('field2') }}>field2</button>
</div>
)
}
}
render(<Parent />, document.getElementById('root'));
CodeSandbox
However if you want to why your way of handling doesn't work as expected it, is because, you are not updating the state of the child components based on the state update in the parent, you were only setting it once in the constructor which is only called once when the component mounts, what you need is to implement the componentWillReceiveProps lifecycle function
Here, I've updated your code to meet your need -https://codesandbox.io/s/llnzm2y95z
Your assumption of child re-rendering is wrong. When the child rerenders the constructor method is not called in other words, constructor is only called once. To use next props and change in states you need to make use of the renders and componentWillReceiveProps. See react-component lifecycle http://busypeoples.github.io/post/react-component-lifecycle/
The problem is when you updated the parent's state using onClick={(e) => { this.update('field1') }} and onClick={(e) => { this.update('field1') }}
You updated the parent's state and this state was again passed to the child. But in the child you are not using this new props. You' re instead using the state, this state was updated only in the constructor, which is not updated after the new props got received. (As the constructor gets called only once)
One way to handle the new props is directly using the props in the render as the component will rerender and the updated props will be available to it.
The other way if you want to make use of the state, then update the state inside componentWillReceiveProps. (I would also want to point out that it is highly not-recommended to do setState inside a componentWillReceiveProps and componentDidMount). So better use the first step.
componentWillReceiveProps(newProps) {
if(newProps !== this.props){
this.setState({newStateObjects})
}
}
I'm teaching myself react with a super simple app that asks the user to type a word presented in the UI. If user enters it correctly, the app shows another word, and so on.
I've got it almost working, except for one thing: after a word is entered correctly, I need to clear the input element. I've seen several answers here about how an input element can clear itself, but I need to clear it from the component that contains it, because that's where the input is checked...
// the app
class AppComponent extends React.Component {
constructor() {
super();
this.state = {
words: ['alpha', 'bravo', 'charlie'],
index: 0
};
}
renderWordsource() {
const word = this.state.words[this.state.index];
return <WordsourceComponent value={ word } />;
}
renderWordinput() {
return <WordinputComponent id={1} onChange={ this.onChange.bind(this) }/>;
}
onChange(id, value) {
const word = this.state.words[this.state.index];
if (word == value) {
alert('yes');
var nextIndex = (this.state.index == this.state.words.count-1)? 0 : this.state.index+1;
this.setState({ words:this.state.words, index:nextIndex });
}
}
render() {
return (
<div className="index">
<div>{this.renderWordsource()}</div>
<div>{this.renderWordinput()}</div>
</div>
);
}
}
// the input component
class WordinputComponent extends React.Component {
constructor(props) {
this.state = { text:''}
}
handleChange(event) {
var text = event.target.value;
this.props.onChange(this.props.id, text);
}
render() {
return (
<div className="wordinput-component">
<input type="text" onChange={this.handleChange.bind(this)} />
</div>
);
}
}
See where it says alert('yes')? That's where I think I should clear the value, but that doesn't make any sense because it's a parameter, not really the state of the component. Should I have the component pass itself to the change function? Maybe then I could alter it's state, but that sounds like a bad idea design-wise.
The 2 common ways of doing this is controlling the value through state in the parent or using a ref to clear the value. Added examples of both
The first one is using a ref and putting a function in the child component to clear
The second one is using state of the parent component and a controlled input field to clear it
class ParentComponent1 extends React.Component {
state = {
input2Value: ''
}
clearInput1() {
this.input1.clear();
}
clearInput2() {
this.setState({
input2Value: ''
});
}
handleInput2Change(evt) {
this.setState({
input2Value: evt.target.value
});
}
render() {
return (
<div>
<ChildComponent1 ref={input1 => this.input1 = input1}/>
<button onClick={this.clearInput1.bind(this)}>Clear</button>
<ChildComponent2 value={this.state.input2Value} onChange={this.handleInput2Change.bind(this)}/>
<button onClick={this.clearInput2.bind(this)}>Clear</button>
</div>
);
}
}
class ChildComponent1 extends React.Component {
clear() {
this.input.value = '';
}
render() {
return (
<input ref={input => this.input = input} />
);
}
}
class ChildComponent2 extends React.Component {
render() {
return (
<input value={this.props.value} onChange={this.props.onChange} />
);
}
}
ReactDOM.render(<ParentComponent1 />, document.body);
<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>
I had a similar issue: I wanted to clear a form which contained multiple fields.
While the two solutions by #noveyak are working fine, I want to share a different idea, which gives me the ability to partition the responsibility between parent and child: parent knows when to clear the form, and the items know how to react to that, without using refs.
The idea is to use a revision counter which gets incremented each time Clear is pressed and to react to changes of this counter in children.
In the example below there are three quite simple children reacting to the Clear button.
class ParentComponent extends React.Component {
state = {revision: 0}
clearInput = () => {
this.setState((prev) => ({revision: prev.revision+1}))
}
render() {
return (
<div>
<ChildComponent revision={this.state.revision}/>
<ChildComponent revision={this.state.revision}/>
<ChildComponent revision={this.state.revision}/>
<button onClick={this.clearInput.bind(this)}>Clear</button>
</div>
);
}
}
class ChildComponent extends React.Component {
state = {value: ''}
componentWillReceiveProps(nextProps){
if(this.props.revision != nextProps.revision){
this.setState({value : ''});
}
}
saveValue = (event) => {
this.setState({value: event.target.value})
}
render() {
return (
<input value={this.state.value} onChange={this.saveValue} />
);
}
}
ReactDOM.render(<ParentComponent />, document.body);
<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>
EDIT:
I've just stumbled upon this beautifully simple solution with key which is somewhat similar in spirit (you can pass parents's revision as child's key)
Very very very simple solution to clear form is add unique key in div under which you want to render form from your child component key={new Date().getTime()}:
render(){
return(
<div className="form_first_step fields_black" key={new Date().getTime()}>
<Form
className="first_step">
// form fields coming from child component
<AddressInfo />
</div>
</Form>
</div>
)
}
I'm trying to use the react-bootstrap checkbox (https://react-bootstrap.github.io/components.html#forms-controls) and I need to fire an event when it changes state. It would also be great to be able to programatically un/check it and/or tell if it is checked. Unfortunately when the code is transpiled and rendered it wraps the input in a div.
How can I find this in the dom and manipulate it?
My code looks similar to this:
import React, { PropTypes } from 'react';
import { Checkbox } from 'react-bootstrap';
const EditItem = (props) => {
return (
<div>
<Checkbox style={{ marginLeft: '15px' }} >{props.itemLable}</Checkbox>
</div>
);
};
export default EditItem;
And the browser renders this:
...
<div class="checkbox" style="margin-left: 15px;">
<label>
<input type="checkbox">
</label>
</div>
...
I see the inputRef prop in the documentation but I can't find any examples of this or get it to work myself.
There are two ways: The React way and the not-so-React way.
The React way is to set the child component's state by passing it props and respond to changes in its state by attaching event handlers. In the case of Checkbox, that means setting the checked and onChange props.
Note in the below example how the parent component (App) keeps track of the Checkbox's state and can both set it with this.setState and query it with this.state.checkboxChecked.
const { Checkbox, Button } = ReactBootstrap;
class App extends React.Component {
constructor() {
super();
this.state = { checkboxChecked: false };
this.handleChange = this.handleChange.bind(this);
this.handleIsItChecked = this.handleIsItChecked.bind(this);
this.handleToggle = this.handleToggle.bind(this);
}
render() {
return (
<div>
<Checkbox
checked={this.state.checkboxChecked}
onChange={this.handleChange} />
<Button type="button" onClick={this.handleToggle}>Toggle</Button>
<Button type="button" onClick={this.handleIsItChecked}>Is it checked?</Button>
</div>
);
}
handleChange(evt) {
this.setState({ checkboxChecked: evt.target.checked });
}
handleIsItChecked() {
console.log(this.state.checkboxChecked ? 'Yes' : 'No');
}
handleToggle() {
this.setState({ checkboxChecked: !this.state.checkboxChecked });
}
}
ReactDOM.render(<App/>, document.querySelector('div'));
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react-bootstrap/0.30.8/react-bootstrap.min.js"></script>
<div></div>
The not-so-React way is to get a reference to the rendered DOM element and access its checked property directly. I don't recommend this, because it necessarily pollutes your lovely functional React code with icky imperative code. Nevertheless, with React-Bootstrap you can do it by setting the inputRef prop, as in the below example:
const { Checkbox, Button } = ReactBootstrap;
class App extends React.Component {
constructor() {
super();
this.handleIsItChecked = this.handleIsItChecked.bind(this);
this.handleToggle = this.handleToggle.bind(this);
}
render() {
return (
<div>
<Checkbox
onChange={this.handleChange}
inputRef={ref => this.myCheckbox = ref} />
<Button type="button" onClick={this.handleToggle}>Toggle</Button>
<Button type="button" onClick={this.handleIsItChecked}>Is it checked?</Button>
</div>
);
}
handleIsItChecked() {
console.log(this.myCheckbox.checked ? 'Yes' : 'No');
}
handleToggle() {
this.myCheckbox.checked = !this.myCheckbox.checked;
}
}
ReactDOM.render(<App/>, document.querySelector('div'));
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react-bootstrap/0.30.8/react-bootstrap.min.js"></script>
<div></div>
Thanks for the above answers. I generalized the above slightly for use when you have more than one checkbox in a given component:
constructor() {
super();
this.state = { YourInputName: false };
this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
}
render() {
return (
<div>
<Checkbox
name="YourInputName"
onChange={this.handleCheckboxChange} />
</div>
);
}
handleCheckboxChange(event) {
const target = event.target
const checked = target.checked
const name = target.name
this.setState({
[name]: checked,
});
}
Have you tried setting an onChange property to your checkbox?
handleChange(event) {
this.setState(*set checkbox state here*);
}
<Checkbox onChange={this.handleChange}></Checkbox>