Why do I need to add .isToggleOn? - javascript

In React Docs, handling events article: how state is being updated to the opposite boolean value, I have a question.
Why do we need to add .isToggleOn after isToggleOn: !prevState
Why can't I just simply write isToggleOn: !prevState?
prevState is {isToggleOn: true}. So !prevState should be {isToggleOn: false}. Am I right?
It confuses me, because it sounds like {property: opposite of the boolean.property}.
I know what prevState is and I know .setState() is updating the state.
Please help me better understand this. Thank you so much in advance!
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

prevState is an object, so you cannot change the properties inside it by using "!" on the whole object. What you need is to change a value within this object, which has key "isToggleOn". Thereby, by using
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
you access this value by key "isToggleOn" and change it to the opposite

In react, the state object is a collection of values, not just a single value. In order to update a specific piece of your state, you need to pass the key of that specific state value in order for it to know what to change.
For example, your state value could be something like this:
this.state = {
isToggleOn: true,
otherValue: false
}
And when you're updating, only the value for the specific key you pass is updated. So if you were to run
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
only the isToggleOn value would change and the otherValue field would remain as false.

Related

React.js understanding setState()

I'm learning React.js and reading through react.js official docs. There is a example presented by the official docs, that I have questions for:
original code:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
my question is :
in the handleClick method, why can't this.setState be written as(without the arrow function):
handleClick() {
this.setState({
isToggleOn: !prevState.isToggleOn
});
}
The reason why you can't do that is that prevState will be undefined and you can't access property key on the undefined object. Whenever you want to change logic based on your previous state you should be using callback function so you can avoid unnecessary direct mutations of state.
In this case both will work. But sometimes you get unexpected output when changing the state on the previous state value. For more info go to
React's setState method with prevState argument
You can understand there.

react native state TypeError: One of the sources for assignhas an enumerable key on the prototype chain

I'm having trouble understanding state and setState and can't get my code to work:
constructor:
constructor(){
super();
this.state = {
Ingredient : getRandomIngredient(baseArray)
}
}
button:
<Button title="Mix Salad"
onPress = {()=>this.handleButtonPress()}
/>
function:
handleButtonPress= () => {
this.setState(
this.Ingredient = getRandomIngredient(baseArray)
)
}
The error occurs once i press the button.
Question a) How do I use state and setState correctly?
Question b) The initial state doesn't persist through the render() function. My Ingredient object remains undefined. That probably isn't intended. What can I do that the Ingredient object retains it's values?
this is wrong syntax
this.setState(
this.Ingredient = getRandomIngredient(baseArray)
)
correct :
this.setState({ Ingredient : getRandomIngredient(baseArray) })
SetState function take ALWAYS and object parameter
EDit :
take care about async function, if getRandomIngredient() take time to return value so Ingredient will be null
You need to use an object in your setState.
handleButtonPress = () => {
this.setState({
Ingredient: getRandomIngredient(baseArray)
});
}

Get state right after setState()

I know setState() does not immediately mutate this.state. So in the code below, checkbox is always unchecked after clicking the button. How to fix this?
handleClick = () => {
this.setState({tick: !this.state.tick})
}
render() {
return (
<button type='button' onClick={() => this.handleClick()} >
<input type="checkbox" value={this.state.tick} />
Tick here
</button>
)
}
use checked instead of value:
<input type="checkbox" checked={this.state.tick} />
from the spec:
checked: Boolean; if present, the checkbox is currently toggled on
value: The string to use as the value of the checkbox when submitting the form, if the checkbox is currently toggled on
ic3b3rg's answer highlights what needs to be changed in the code for the checkbox to work. I'm going to highlight a few other things that could be improved.
Checkbox check state should be controlled with checked attribute
Don't declare your event handlers with arrow functions as it will create a new anonymous function during every single render. It's a good idea to bind a function to the class and pass it to the event handler.
Something like this
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
...
}
// render
<button type = 'button' onClick = {this.handleClick} >
When you want to update state based on existing state value, it's usually not a good idea to call this.state.key directly in your setState function as setState is an async call and you can't exactly say what the value of your current state will be. Instead, if you use this.setState((prevState, props) => ({}) callback, your state value will be updated based on what your existing state value was during invocation.
Change this
this.setState({tick: !this.state.tick})
to
this.setState((prevState, props) => ({
tick: !prevState.tick
}));
Here's a full working example
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
tick: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// when updating state values from existing state values
// you should use not use value: !this.state.value directly
this.setState((prevState, props) => ({
tick: !prevState.tick
}));
}
render() {
return (
<button type = 'button' onClick={this.handleClick} >
<input type = "checkbox" checked={this.state.tick} />Tick here
</button>
);
}
}
ReactDOM.render( <
Example / > ,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>

React setState with dynamic key and object value not working as expected

i'm facing an issue with react's method (setState), hope you can help.
I have a handleChange method using dynamic keys to 'persist' data in the state.. i looks like this:
handleChange = (event, group) => {
event.persist(); //Used to avoid event recycling.
this.setState(
prevState => ({
...prevState,
[group]: { ...prevState[group], [event.target.name]: event.target.value }
}),
() => console.log("state", this.state)
);
};
this method works pretty well when theres just one 'instance' of my custom component using the mentioned handleChange method. The problem began when i wanted to have several components using that method, because when called, its overriding the prevState value. For example:
Initial state: {mockedValue:'Im here to stay'}
then i call handleChange for group 'alpha', to add to this values {name:a},
Next state: {alpha:{name:a},mockedValue:'Im here to stay'}
then i call handleChange for group 'beta', to add to this values {otherName:b},
expected state: {alpha:{name:a}, beta:{otherName:b},mockedValue:'Im here to stay'}
Next state : beta:{otherName:b},mockedValue:'Im here to stay'}
Not sure why this is happening, perhaps i'm misunderstanding some concept, the fact is that i don't have idea why this is not working as expect, (perhaps it's because computed name value, but not sure..) Do you have any idea how to solve this?
Thanks for reading! :)
Update
Code in sandbox: https://codesandbox.io/s/v3ok1jx175
Update2: SOLVED
Thanks for your support Thollen and DevSerkan, i really appreciate it.
The problem was that i had the handleChange event at the wrong level... it means that i was defining the handleChange method inside the child Componet, for instance:
class Parent extends React.Component {
render(){
return(
<div>
<Child/>
<Child/>
<Child/>
</div>
);
}
}
so there was just one 'instance' of handleChange method shared by all the 'instances' , it's a wrong approach. to solve this, i modified Parent like this:
class Parent extends React.Component {
handleChange(){
//updateState Operations here...
}
render(){
return(
<div>
<Child handleChange = {this.handleChange}/>
<Child handleChange = {this.handleChange}/>
<Child handleChange = {this.handleChange}/>
</div>
);
}
}
in this way, i removed the responsibility of handling change from the 'top level child' to the parent, where the child components were being used.

React setState + Where does 'prevState' come from?

I just started learning React and JavaScript.
While going through the tutorial, I got to this example code of a component, which creates a toggle button.
This is part of the code:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({ // prevState?
isToggleOn: !prevState.isToggleOn
}));
}
2 things that are bugging me here:
Where did the prevState argument come from?
I don't see anything like var prevState = this.state; before calling it, and still, it works.
The syntax of the arrow function: why the parentheses after the arrow?
Why doesn't the usual arg => { statement; } syntax work here?
Sorry for the newbie questions...
prevState is provided by React along with props, both of which are optional.
Update 04/13/19: React has changed the setState function documentation by renaming prevState to updater. The callback function still takes two arguments; the state and props at the time the change is being applied.
The parenthesis allow multiple lines where if you didn't use the parenthesis you'd be forced to used a return. You could use a single line but you don't need the curly braces.
Update: I forgot to mention a specific case where it is required to have parenthesis. If you're returning an object without a return statement you must wrap it in parenthesis. Thank you #joedotnot for catching that. So () => {foo: true} will throw an error because it looks like a function and foo: true is an invalid line. To fix this it must look like () => ({ foo: true })
Im use this. (Example)
const [modal, setModal] = useState(false);
const [dataAction, setDataAction] = useState({name: '', description: ''});
const _handleChangeName = (data) => {
if(data.name)
setDataAction( prevState => ({ ...prevState, name : data.name }));
if(data.description)
setDataAction( prevState => ({ ...prevState, description : data.description }));
};

Categories

Resources