Toggle React checkboxes without state - javascript

I have some checkboxes that I'm just using as filters for data that need to run a function on click. Usually, and all tutorials ive read, have suggested to handle checkbox checked attribute using state. Is it possible to do this without using state? I don't really want to declare all the different checkboxes in my state just to toggle them on and off. I was hoping I could do something like this
<input type="checkbox" checked={true} onChange={(e) => e.target.checked = false } />

Sure you can, using uncontrolled components, then using refs to get the values. It's considered "quick and dirty", but you can do it no problem. See this article for more detailed information: https://reactjs.org/docs/uncontrolled-components.html.

Related

How to tell if a React web-component button is disabled in Cypress?

We're in the process of replacing our custom react components with components from the company's design system.
These are web-components and it has been made a react-wrapper to make them work in React.
The element is rendered like this in our app:
<custom-button title="" data-test-id="save" disabled mode="primary">
#shadow-root
<button data-mode="primary" size="small" type="button" title="" disabled>Save</button>
</custom-button>
In Cypress I have tried to check if it is disabled like so:
cy.getByTestId('save').should('be.disabled'); //Doesn't work, but its the way I want to do it
cy.getByTestId('save').find('button').should('be.disabled'); // Works
The first way doesn't work but its the way i want to do it because thats how all our tests work today.
I want to having having to do the second way because that means we have to handle buttons from our design-system different from regular buttons.
Does anyone know why the first way doesnt work? Even though the <custom-button> has the disabled attribute applied to it in the DOM?
The difference is between attribute and property.
Under the hood cy.getByTestId('save').should('be.disabled') is checking that the element has property disabled. The standard button translates the attribute disabled into a corresponding property, so it passes the above assertion.
The custom button obviously does not have that behavior, so it might be difficult to treat custom-button the same as button.
One thing that works for your sample is
cy.getByTestId('save').should('have.attr', 'disabled')
This should work for all occurrences of custom-button (if my assumption about it's behavior is correct).
If you have trouble with standard button, you can check both:
cy.getByTestId('save').should($el => {
return $el.attr('disabled').length > 0 || $el.prop('disabled').length > 0
})
You can make a custom assertion if that's a pain to code everywhere.
IMO using .find('button') isn't optimal, since it's an internal implementation of the custom-button.
As the comments state, you only retrieve the custom-button element and not the button, which has the disabled attr.
The working solution is fine.
cy.getByTestId('save').find('button').should('be.disabled')
cy.getByTestId('save').contains(/save/i).should('be.disabled') // find based on text instead
You can check if in your design-system repo if a data-testid can be passed to the component or add the change yourself, which could be a more cumbersome process.

Provide both :value and v-model on a radio type field

<input type="radio" :value="myValue" v-model="value" />
I'm trying to create a radio button and wrap it in a component, so value becomes a variable. The problem is that I'm getting the following error:
:value="myValue" conflicts with v-model on the same element because the latter already expands to a value binding internally
I've tried to replace v-model with direct bindings but I cannot replicate the same functionality. Why does this error appear in this case? This is taken directly from official docs for the radio buttons.
v-model is just shorthand for :value="someVar" #input="someVar = $event". meaning you are assigning the value twice. Depending on your need you can do :value="someVar" and then have a custom function handle the input like so:
#input="someFunc" this function would accept the input (by default) and then you could update myVar as you desire.
See here for a more detailed explanation

quirks of input element in React

I'm new to React, sorry if my questions are trivial.
In React, if I write:
<input value="" />
then it will be an read-only field, and React forces me to add an onChange handler as:
<input value={this.state.greeting} onChange={this.handleChange} />
where handleChange() update component's state.greeting, therefore value gets updated too
Below are my questions:
Q1-why <input value="" /> is not read-only in plain html but read-only in React? How does React make it read-only
Q2-I found that if I write the code as below it also works, the input is not read-only
<input onChange={this.handleChange} />
and isn't that this approach better and more concise? because the internal value will get updated automatically in the browser, therefore we don't need to include an value attribute to read the data back from the state, which is unnecessary in most of times, so why I always see code like:
<input value={this.state.greeting} onChange={this.handleChange} />
Additional info:
some says it is controlled form elements that needs to have value attribute, but why we need to have a value attribute to read from the state? and when we type sth into the input, the onChange handler already updates the state, so it is still controlled.
To know how React makes your tags readonly, you will need to study the source-code that runs at your end and/or view the generated HTML. If still unsure about it, then you might want to send your first question to the authors of the tool.
The state is not on the server, unless you are polling or doing something of the like. It's in your browser as well. The value property specifies the initial value of your HTML element, that is, before you do anything your tag will have a value. In your case, your tag is controlled by React, but you need to initialize it. Benefits:
you will have the initial value
you will have a more readable code
your code will be written in the React-way, so you will not need to worry of unpleasant surprises

ReactJS - binding focus

My component has a list of child components, each with a text input. My redux store has an activeIndex property which stores which input is being edited. When they hit enter, redux dispatches and updates the active index appropriately. The problem is that the focus is not changing. This was my original (non working) code.
<input autoFocus={this.props.index == this.props.activeInput}
This code DID set the initial focus correctly, but did not update.
Am I correct in assuming that React's dom-diffing algorithm doesn't include the focus information, and therefore decided nothing needed to be re-rendered? My solution wound up being this:
<input ref='input' autoFocus={this.props.index == this.props.activeInput}
componentDidUpdate(){
if (this.props.index == this.props.activeInput){
ReactDOM.findDOMNode(this.refs.input).focus();
}
}
which does work. Would this be the ideal solution in my case, or is there a more "react" way of accomplishing this?
The reason your component does not update focus is not because of react's diff engine. If your props are different, react will re-render the component.
Your issue stems (I think) from the way autofocus works: autofocus is only checked and applied on initial rendering of the page.
Your component is rerendered by react, but the second time around, HTML ignores the autofocus attribute.
So your second solution is a good react-y way to solve.

React: Will a state change cause an entire component to be redrawn?

I'm creating a form in react that has conditional flow. For example two input fields might be hidden when some select option is chosen. Is it a good idea to create states based on the select options and make the visibility of the input elements to depend on the current state. Or shall I add refs to the input elements and make the select cause a change event which will be used to manipulate the visibility of the inputs?
Unless you have any complicated logic for deciding whether to draw an input or not I think it's perfectly fine, even encouraged, to simply tie it to some state variable. Here's an example using Reacts two-way binding addon:
var MyForm = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {hasName: false};
},
render: function() {
var nameInput = null;
if (this.state.hasName) {
nameInput = <label>
Name:
<input type="text" />
</label>;
}
return <form>
<label>
<input type="checkbox" checkedLink={this.linkState('hasName')} />
Do you have a name?
</label>
<br/>
{nameInput}
</form>;
}
});
React.render(<MyForm/>, document.body);
http://jsfiddle.net/p4u1qhym/
And when you're using event handlers you should still set a state variable for the input: Even though React is smart enough to keep any DOM state intact during re-rendering (e.g. a visibility styling option), it won't always work. Imagine for example a situation where you serialize the forms state and want to use it to initialize another form later on. React won't be able to infer that the name input should not be displayed, and renders it.
There still exist situations when it's useful to use this.refs however, for example when setting the focus to a particular input, as described here.
From the title of your question I assume you are worrying about performance: Yes, the entire component will be re-rendered, but only in virtual DOM. React then finds all the differences to the actual DOM and only applies the changes required for the two to match. You can read about it here. As this whole process is very efficient, there should be virtually no difference in performance to setting some style attribute on the actual DOM node using this.refs. And it's a lot less verbose!

Categories