What's wrong with my react method below
toggleReply = () => {
this.setState(prevState => ({ reply: !prevState.reply }))
}
I know I can dothis.setState({reply: !this.state.reply})but above code will also work, but it didn't, any clue?
Your setState works, as per the docs - try this snippet below. This is assuming you Component class is correctly defined and your toggleReply handler is either bound to this during construction, or you're using an arrow function to call it.
class Thing extends React.Component {
constructor(props) {
super(props);
this.state = { reply: false };
this.toggleReply = this.toggleReply.bind(this);
}
toggleReply() {
this.setState(prevState => ({ reply: !prevState.reply }))
}
render() {
return (
<div>
<button onClick={this.toggleReply}>Toggle Reply</button>
<span>{` ${this.state.reply}`}</span>
</div>
);
}
}
ReactDOM.render(
<Thing />,
document.getElementById('root')
);
<script src=" https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<div id="root"></div>
You need to make sure ES7 class properties are enabled:
https://babeljs.io/docs/plugins/transform-class-properties/
That is what allows you to use the arrow function inside of your class with proper this bindings. Otherwise you have to manually bind it using a regular function like the other answer describes.
Related
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.
So, i've readed that doing something like this
<SomeButton onPress={() => { this.someFunction(args)}} />
is bad because it is creating a new instance of function for each render cycle.
But how do i pass args in React-Native then?
Creating a new inline function is fine in many cases, but if you have a lot of SomeButton components it might be worth passing the args as props to the component and use that as arguments in the component's onPress instead.
Example
class SomeButton extends React.Component {
handleClick = () => {
const { onClick, someProp } = this.props;
onClick(someProp);
};
render() {
return <button onClick={this.handleClick}>Click me</button>;
}
}
class App extends React.Component {
handleClick = arg => {
console.log(arg);
};
render() {
return <SomeButton onClick={this.handleClick} someProp="foo" />;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react#16.4.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16.4.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
One can use HTML data-* Attributes.
someFunction
someFunction= (event)=>{
console.log(event.target.dataset.mykey )
}
render:
<Button data-mykey onPress={this.someFunction} />
In which context? I would say it depends if that is what you want or need to have. In general you could use properties instead of passing arguments.
I guess you read something about re-rendering (which may result in loss of performance); here is what is said about it in the react-native guide:
https://facebook.github.io/react-native/docs/direct-manipulation
I looked at many other answers but I couldn't figure it out. Here is my code:
// userInputActions.js
...
export function dummy() {
console.log('dummy function called');
}
...
// *userInputPage.js*
import * as userInputActions from '../actions/userInputActions';
class UserInput extends React.Component {
constructor(props) {
super(props);
this.state = {
};
// When un-commented it shows '*f dummy()*' is imported
// console.log('actions: ', userInputActions);
this.dummy = this.dummy.bind(this);
}
render () {
return (
<div className="container-fluid align-items-center">
<FieldLevelValidationForm onSubmit={this.dummy}/>
</div>
);
}
}
const mapStateToProps = (state) => ({
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
{
...userInputActions
}, dispatch
);
export default connect(mapStateToProps, mapDispatchToProps)(UserInput);
Note 'FieldLevelValidationForm' is a redux-form and onSubmit is one of the form function arguments.
I tried various things and the bind function does not work. Can someone please let me know where am I going wrong. I think it has something to do with the render() function and the lifetime of the component but I do not know enough yet.
Edit
Thank you - learned a lot from all answers. All of them work. I wish I could give more than one check-mark. However, I think the most appropriate use for my case is to call it as a prop and dispatch an action as so on.
The dummy function is passed as props, so you should access it with this.props.dummy in your render() instead.
There's also no need to bind it to this as it's not using the this instance.
The dummy function you are trying to bind is not in this class. So it would just be:
this.dummy = userInputActions.dummy.bind(this);
Function definition of dummy is missing.
constructor(props) {
super(props);
this.state = { };
this.dummy = this.dummy.bind(this);
}
dummy(e) {
// form submission action
userInputActions.dummy(); // maybe
}
render () {
return (
<div className="container-fluid align-items-center">
<FieldLevelValidationForm onSubmit={this.dummy}/>
</div>
);
}
I have a React component and I want to toggle a css class when clicked.
So I have this:
export class myComponent extends React.Component {
constructor() {
super();
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div>
<div onClick={this.clicked}><span ref="btn" className="glyphicon"> </span></div>
</div>
);
}
handleClick() {
this.refs.btn.classList.toggle('active');
}
componentDidMount() {
this.refs.btn.addEventListener('click', this.handleClick);
this.setState({
clicked: this.state.clicked = true,
});
}
componentWillUnmount() {
this.refs.btn.removeEventListener('click', this.handleClick);
this.setState({
clicked: this.state.clicked = false,
});
}
}
This problem is that ESLint keeps telling me "this.refs" is depreciated.
What do I do instead? How can I fix it so it's not using depreciated code?
The Lint rule you are referring to is called no-string-refs and warns you with:
"Using string literals in ref attributes is deprecated (react/no-string-refs)"
You are getting this warning because have implemented the deprecated way of using refs (by using strings). Depending on your React version, you can do:
React 16.3 and later
constructor() {
super();
this.btnRef= React.createRef();
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div>
<div onClick={this.addVote}><span ref={this.btnRef} className="glyphicon"> </span></div>
</div>
);
}
React 16.2 and older
constructor() {
super();
this.btnRef; //not necessary to declare the variable here, but I like to make it more visible.
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div>
<div onClick={this.addVote}><span ref={(el) => this.btnRef = el} className="glyphicon"> </span></div>
</div>
);
}
For even better readability, you could also do:
render() {
let myRef = (el) => this.btnRef = el;
return (
<div>
<div onClick={this.addVote}><span ref={myRef} className="glyphicon"> </span></div>
</div>
);
}
Have a look at what the official documentation says on Refs and the DOM, and this section in particular:
Legacy API: String Refs
If you worked with React before, you might be
familiar with an older API where the ref attribute is a string, like
"textInput", and the DOM node is accessed as this.refs.textInput. We
advise against it because string refs have some issues, are considered
legacy, and are likely to be removed in one of the future releases. If
you're currently using this.refs.textInput to access refs, we
recommend the callback pattern instead.
The reason this ESLint rule exists is that string Refs are on their way out. However, for the code above I would recommend to not use a Ref in the first place.
Don't Overuse Refs
React's advantage is that it is declarative. Meaning, we have state and an expression (returned JSX) of how the UI (more precisely the DOM) should look given a certain state.
Whatever can be done using just state and UI expression, should be done this way. The problem with the use of a Ref in the code above is that it makes the code imperative. We can't understand how the DOM will look just from the JSX. Here is how you could achieve the same result in a declarative way:
export class myComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
};
}
handleClick = () => { // with arrow function there is no need for binding.
this.setState(
prevState => {
return {
active: !prevState.active
}
}
)
}
render() {
return (
<div>
<span
onClick={this.handleClick}
className={`glyphicon ${this.state.active && "active"}`}
>
Hello World
</span>
</div>
);
}
}
Refs should be used when state and UI expression aren't enough, and you need access to the actual DOM. For example, focusing on an input field, scrolling to an element, or getting the exact width and height of an element.
If you do use Refs, avoid string refs
String refs harm performance, aren't composable, and are on there way out.
string refs have some issues, are considered legacy, and are likely to
be removed in one of the future releases. [Official React documentation]
[resource1][1], [resource2][1]
Option #1: Use React.createRef
class MyComponent extends Component {
constructor(props) {
super(props)
this.myRef = React.createRef() // create a ref object
}
render() {
return <div ref={this.myRef}></div> // Attach the ref property to a dom element
}
}
Option #2: Use a ref callback
class MyComponent extends Component {
constructor(props){ // Optional, declare a class field
super(props)
this.myRef=null
}
render() {
return <div ref={ (ref) => this.myRef=ref }></div>
} // Attach the dom element to a class field
}
you can try a more declarative way. I changed your code to reflect this. You just need to remind that a component will refresh and call render in every state/props change. So, we can create the class of your element inside render method.
import React from 'react'
export default class myComponent extends React.Component {
constructor() {
super();
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
render() {
let btnClass = 'glyphicon'
if(this.state.clicked){
btnClass+=' active'
}
return (
<div>
<div onClick={this.handleClick}><span ref="btn" className={btnClass}> </span></div>
</div>
);
}
handleClick() {
this.setState({
clicked: !this.state.clicked
})
}
}
I'd like to know how to toggle a boolean state of a React component. For instance:
I have a boolean state check in the constructor of my component:
constructor(props, context) {
super(props, context);
this.state = {
check: false
};
};
I am trying to toggle the state each time my checkbox is clicked, using the this.setState method:
<label>
<input
type=checkbox"
value="check"
onChange={(e) => this.setState({check: !check.value})}
/>
Checkbox
</label>
Of course I get a Uncaught ReferenceError: check is not defined.
So how can I achieve this?
Since nobody posted this, I am posting the correct answer. If your new state update depends on the previous state, always use the functional form of setState which accepts as argument a function that returns a new state.
In your case:
this.setState(prevState => ({
check: !prevState.check
}));
See docs
Since this answer is becoming popular, adding the approach that should be used for React Hooks (v16.8+):
If you are using the useState hook, then use the following code (in case your new state depends on the previous state):
const [check, setCheck] = useState(false);
// ...
setCheck(prevCheck => !prevCheck);
You should use this.state.check instead of check.value here:
this.setState({check: !this.state.check})
But anyway it is bad practice to do it this way. Much better to move it to separate method and don't write callbacks directly in markup.
Upd:
As pointed out in comments this approach might lead to unexpected results since React's state is asynchronous.
The correct way in this case will be to use callback:
this.setState(({ check }) => ({ check: !check }));
Here's an example using hooks (requires React >= 16.8.0)
// import React, { useState } from 'react';
const { useState } = React;
function App() {
const [checked, setChecked] = useState(false);
const toggleChecked = () => setChecked(value => !value);
return (
<input
type="checkbox"
checked={checked}
onChange={toggleChecked}
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>
Use checked to get the value. During onChange, checked will be true and it will be a type of boolean.
Hope this helps!
class A extends React.Component {
constructor() {
super()
this.handleCheckBox = this.handleCheckBox.bind(this)
this.state = {
checked: false
}
}
handleCheckBox(e) {
this.setState({
checked: e.target.checked
})
}
render(){
return <input type="checkbox" onChange={this.handleCheckBox} checked={this.state.checked} />
}
}
ReactDOM.render(<A/>, document.getElementById('app'))
<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="app"></div>
Try:
<label><input type=checkbox" value="check" onChange = {(e) => this.setState({check: !this.state.check.value})}/> Checkbox </label>
Using check: !check.value means it is looking for the check object, which you haven't declared.
You need to specify that you want the opposite value of this.state.check.
You could also use React's useState hook to declare local state for a function component. The initial state of the variable toggled has been passed as an argument to the method .useState.
import { render } from 'react-dom';
import React from "react";
type Props = {
text: string,
onClick(event: React.MouseEvent<HTMLButtonElement>): void,
};
export function HelloWorldButton(props: Props) {
const [toggled, setToggled] = React.useState(false); // returns a stateful value, and a function to update it
return <button
onClick={(event) => {
setToggled(!toggled);
props.onClick(event);
}}
>{props.text} (toggled: {toggled.toString()})</button>;
}
render(<HelloWorldButton text='Hello World' onClick={() => console.log('clicked!')} />, document.getElementById('root'));
https://stackblitz.com/edit/react-ts-qga3vc
I found this the most simple when toggling boolean values. Simply put if the value is already true then it sets it to false and vice versa. Beware of undefined errors, make sure your property was defined before executing
this.setState({
propertyName: this.propertyName = !this.propertyName
});
Depending on your context; this will allow you to update state given the mouseEnter function. Either way, by setting a state value to either true:false you can update that state value given any function by setting it to the opposing value with !this.state.variable
state = {
hover: false
}
onMouseEnter = () => {
this.setState({
hover: !this.state.hover
});
};
I was landed in this page when I am searching to use toggle state in React component using Redux but I don't find here any approach using the same.
So, I think it might help someone who was struggling to implement toggle state using Redux.
My reducer file goes here. I get the initial state false by default.
const INITIAL_STATE = { popup: false };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case "POPUP":
return {
...state,
popup: action.value
};
default:
return state;
}
return state;
};
I change state on clicking the image. So, my img tag goes here with onClick function.
<img onClick={togglePopup} src={props.currentUser.image} className="avatar-image avatar-image--icon" />
My Toggle Popup function goes below, which call Dispatcher.
const togglePopup = ev => {
ev.preventDefault();
props.handlePopup(!props.popup);
};
This call goes to below mapDispatchToProps function which reflects back the toggled state.
const mapDispatchToProps = dispatch => ({
handlePopup: value => dispatch({ type: "POPUP", value })
});
Thank you.
Set: const [state, setState] = useState(1);
Toggle: setState(state*-1);
Use: state > 0 ? 'on' : 'off';
I know this is an old question, but this is a very common use case.
If you want to simply toggle a boolean state with hooks:
setIsToggled(state => !state)
You just provide a callback which accepts current state.
const { Component, useState } = React;
function App(){
return (
<div>
<ToggleClassComp />
<ToggleFuncComp />
</div>
)
}
// WITH REACT CLASS COMPONENT
// import React, { Component } from 'react';
class ToggleClassComp extends Component {
constructor(props, context){
super(props, context);
this.state = {
check : false
}
}
render(){
return (
<div>
<p>{this.state.check ? 'Welcome User' : 'Welcome Visitor'}</p>
<button
onClick={() => this.setState({check: !this.state.check}) }>
{this.state.check ? 'Logout' : 'Login'}</button>
</div>
)
}
}
// WITH FUNCTION COMPONENT
// import React, { useState } from 'react';
function ToggleFuncComp(){
const [ check , setCheck ] = useState(false)
return(
<div>
<p>{check ? 'Welcome User' : 'Welcome Visitor'}</p>
<button onClick={()=> setCheck(!check )}>
{check ? 'Logout' : 'Login'}</button>
</div>
)
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>