React setState not firing in first time - javascript

i saw similar questions but can't get some solution.
i have some input when you paste some text to input i'm trying to set it to state and render this text. But when paste in first time state not change in second time when paste everything works.
I don't understand why it happen i already used some setTimeOut function too for it but not helped.
here is my code:
import React from "react";
import { render } from "react-dom";
class App extends React.Component {
constructor() {
super();
this.state = {
no: ""
};
}
pasteSomeText = e => {
this.setState({
no: e.target.value
});
};
render() {
return (
<div style={styles}>
{this.state.no}
<input onPaste={event => this.pasteSomeText(event)} />
</div>
);
}
}
render(<App />, document.getElementById("root"));
Here is codeSandBox example: https://codesandbox.io/s/1-react-hello-world-tvscf?fontsize=14

To get the data from the event, use e.clipboardData.getData('text'). See https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
e.target.value gives you the value for the text field before it updates with the paste data, so you can cancel/modify the paste if you want.
pasteSomeText(e) {
this.setState({
no: e.clipboardData.getData('text')
});
};
Side note: with the call from the HTML, you don't need to use this arrow function (which uses more memory), see my example above

Basically the reason why you get empty state on firts onpaste call is that onpaste fires before the input's value is changed. So you get empty event.target.value and for all other calls you get previous value.
And if you still decide to keep going with onpaste you should keep in mind that you can get pasted value with event.clipboardData.getData('Text') but it can differ from what have been pasted in input because of different behavior of clipboardData for different input types.
https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
So for work with clipboard data I will recommend to use DataTransfer module from https://www.npmjs.com/package/fbjs to get more consistant behavior in different systems and browsers.

Is a diferente kind of event you will need to get the clipboard data from the event and set it to the state
const value = e.clipboardData.getData('text')

use
onChange
instead of using
onPaste
Updated https://codesandbox.io/s/1-react-hello-world-h2jgv

Related

React Updating Form Data

I have the following code:
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{firstName: ""}
)
console.log(formData.comments)
function handleChange(event) {
setFormData(prevFormData => {
return {
...prevFormData,
[event.target.name]: event.target.value
}
})
}
return (
<form>
<input
type="text"
placeholder="First Name"
onChange={handleChange}
name="firstName"
value={formData.firstName}
/>
</form>
)
}
I'm trying to understand a few aspects of that that I'm not 100% on, and would appreciate if anyone could advise.
My understanding of the order of operations is as such:
The user types text into the input
onChange runs and triggers the handleChange callback
The handle change callback runs. This triggers the setter function which changes the state.
The form component is re-rendered due to the setter function being run.
I believe this is right, but it leads to a bit of confusion for me:
How is the console.log(formData.comments) being run each time a change is made? Does this happen when the form component is re-rendered? And if so, why doesn't const [formData, setFormData] = React.useState({firstName: ""}); also reset each time?
When my handleChange function runs, it triggers the callback which returns an identical object, except that we reassign one property, which is: [event.target.name] : event.target.value. If event.target.name and event.target.value are coming from what I pass to the input component, and value={formData.firstName}, how does my state ever update? Since I type a new character in the field, but the state isn't updated, and therefore value isn't updated, which means the old value should still be used.
Where can I view more information about event which is passed to my handler function?
Thanks to anyone who can help, I appreciate it!
The console statement runs because of the re-rendering of the component . Since formData is a state and uses useState api , it is not meant to re-initialize . Thats how react works since it compares the DOM to render new changes .
The setFormData is called and although it still contains the previous value since you are hardcoding the input value which is same as before but since the set method api of the useState is called the component is bound to re-render . Again this is how react works
You can always console log the event you passed inside the handler

Changing class state from an imported function in ReactJS

I am trying to change the state of a class from an imported named component so I only need to write the code once. Is this even possible?
I have 3 files ( Login, ForgotPassword, Register ). On ALL of these files I am listening for an "onChange" event on the input fields that all do the same thing as show below:
onChange method:
onChange = (e) => {
this.setState(() => ({ errors: {} }));
let fields = this.state.fields;
fields[e.target.name] = e.target.value;
this.setState(() => {
return {
fields
}
});
};
I'd really like to import this as a named method along with some others that are working already:
import { onFocus, onBlur, onChange } from './Utils/Input';
The issue is (as seen above in the onChange code), that I need to update the class state from this method.
Is this at all possible? I am very new to React, so I might be going about this in the completely wrong way.
Thank you in advance!
When trying to update the state of a component you are always updating the state regarding to a particular this.
You are trying to write on* functions which are independent of the instances you are working with. So it makes no sense to use "this" inside those.
You could pass the instance of the Class to the on-function like this:
https://codesandbox.io/s/focused-cache-zzfvp
Use the method by binding the context to it from inside the class like this
onChange.bind(this)

Warning: This synthetic event is reused for performance reasons happening with <input type="checkbox" />

I've been working on a simple react-redux todo example for a class and I came across several warning messages that show in the console everytime I check and uncheck a checkbox input.
You can see the warnings in the following images.
I also did a google search for the warning message but couldn't find any solution that works. Also, what stroke my attention was that it looks like it was trying to access every property of the native event, and DOM element.
This is the code for the presentational component that has the input checkbox
class TodoItem extends React.Component {
state = {
isChecked: false
};
handleCheckbox = () => {
this.setState({
isChecked: !this.state.isChecked
});
};
render() {
const { todos, onItemClick } = this.props;
const { isChecked } = this.state;
return (
<div>
<ul>
{todos.map((todo, id) => {
return (
<li key={id} onClick={onItemClick}>
<input
onChange={this.handleCheckbox}
type="checkbox"
checked={isChecked}
/>
<label>
<span />
{todo.textInput}
</label>
</li>
);
})}
</ul>
</div>
);
}
}
export default TodoItem;
I uploaded the example on CodeSandbox as well: https://codesandbox.io/s/k0mlxk1yqv
If you want to replicate this error you need to add an Item to the todo List and click the checkbox to check and uncheck a couple of times.
If anyone has any idea why this warning signs keep appearing and how to disable them I would appreciate your input very much :)
This happened because the event implicitly passed to onItemClick is used in an asynchronous context.
As Andre Lemay said, you should assign your needs to local variables and reference them.
In my case, I had this code:
handleInput = e => { // <-- e = synthetic event
this.setState(state => ({ // <-- asynchronous call
data: {
...state.data,
[e.target.name]: e.target.value // <-- this was causing the warnings (e.target is in an asynchronous context)
}
}));
};
Then I changed it to:
handleInput = e => {
const { name, value } = e.target; // <-- moved outside asynchronous context
this.setState(state => ({
data: {
...state.data,
[name]: value
}
}));
};
I'd suggest trying two solutions:
First change
onChange={this.handleCheckbox}
to
onChange={() => this.handleCheckbox()}
If that won't work, in 'handleCheckbox' add event.persist(); Like this:
handleCheckbox = (event) => {
event.persist();
this.setState({
isChecked: !this.state.isChecked
});
};
This may be a little late, but I just came across the same problem and solved in a way that I think might be better than Adam Orlov's answer. I don't believe either answer is directly applicable to the asked question, but this comes up when googling about synthentic events and checkboxes so it's as good a place as any...
I believe Adam is correct in his belief that React will essentially clear all properties of the SyntheticEvent object (which makes sense, since React is telling us that it's reusing the object).
However, unless you need the entire object, I don't think calling event.persist() is the best solution, as according to the documentation, that will remove the object from the pool (presumably they put it there for a good reason).
If you want to access the event properties in an asynchronous way, you should call event.persist() on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.
Instead of doing this, if you only need one or two values from the event object, you can just assign those to local variables, and then reference the local variables inside your own function, like this:
<input type="checkbox" onChange={(event) => {
let checked = event.currentTarget.checked; //store whatever values we need from from the event here
this._someOtherFunction(checked)
} />
In this way, you don't have to restructure your code in any way to avoid doing anything async that relies on event data, and you also don't have to worry about potential performance impacts as you allow React to do what it wants with the event pool.
Similar problem here though my setup is, functional component, Material UI <Textform /> input.
The guy above that mentioned event.persist();, thank you that worked for me, but the first suggestion had no noticeable affect, not sure if thats because Im using functional components and not class components. (I dont use class components anymore, only functional with hooks)
Also note the warning info suggested to use event.persist(). My issue was I was capturing form input using onChange and storing input into my state, after about the second or third character it would throw errors and also crash my app.
Before:
const handleChange = (e) => {
setState((form) => ({
...form,
[e.target.name]: e.target.value,
}));
};
After:
const handleChange = (e) => {
e.persist();
setState((form) => ({
...form,
[e.target.name]: e.target.value,
}));
};
So it appears this is the correct solution to a similar issue, while I was not using a checkbox, I was using a form input, a Material-UI <TextField />. I can remove the single line of
e.persist();
and the code will fail again, add it back, everything is good no crashing no warnings.
for the ones that came to this problem with react native.
i face this problem on a navigation
PersonalProductsScreen.navigationOptions=({navigation})=>{
const handleEditButton=navigation.navigate.bind(this,"EditProduct")
return {
headerTitle:"My Products",
headerRight:<CustomHeaderButton
iconName="ios-add"
title="Add"
iconSize={26}
color={colors.bright}
onPress={handleEditButton}
/>
}
}
pay attention to the method i used . I was trying to bind the navigate method.
This is the refactor:
const handleAddButton=()=>navigation.navigate("EditProduct")

Testing React components - mount vs shallow and simulating events

I have the following React components that I'm trying to test by simulating entry into the input field with id=componentCount. I started using React for the first time less than one week ago, so this framework is very new to me and any help would be appreciated.
I'm also using Semantic UI React for the CSS framework, hence the Form.Group and Form.Input tags
export class SoftwareForm extends React.Component {
constructor(props) {
super(props);
this.state = {
componentCount: 0
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<Form id='softwareForm'>
<Form.Group>
<Form.Input label='Name' placeholder='Component Name' id='componentName' type='text'/>
<Form.Input label='Description' placeholder='Component Description' id='componentDescription' type='text'/>
<Form.Input name='componentCount'
label='Count'
placeholder='Count'
id='componentCount'
type='number'
min='0'
value={this.state.componentCount}
onChange={this.handleInputChange}/>
</Form.Group>
</Form>
);
}
}
Test script
describe('<SoftwareForm />', () => {
it('Count field accepts text input', () => {
const softwareFormComponent = mount(<SoftwareForm />);
const countField = softwareFormComponent.find('#componentCount');
countField.simulate('change', {target: {value: 3}});
expect(softwareFormComponent.state('componentCount')).toBe(3);
});
});
The above test script uses mount for full rendering, but I get the following error, "Method “simulate” is only meant to be run on a single node. 4 found instead."
If I use a shallow mount, the test output is the following
Expected value to be (using ===):
3
Received:
0
This tells me that the simulate method is not working as expected.
Several questions:
Can a shallow render be used in this scenario since I can use the find method to search for the element with the 'componentCount' id attribute or is a full render with a mount necessary since I'm trying to manipulate an input element which is a child of the Form.Group?
Regardless of the answer the question 1, when mount is used, the wrapper that is returned contains 4 nodes - what are these 4 nodes and which one am I supposed to call simulate on if a full render is in fact needed in this case?
I'm struggling due to not having a clear understanding of the structure of the wrapper object that is returned by either shallow or mount.
The idea of the last two statements in the test script is to simulate the change to the value of the number in the input field, have the onChange event handler trigger an update of the componentCount state value and then the perform a comparison using the assert statement. Is this the correct approach?
Trying to answering your questions:
You could use mount, which create test on a full DOM rendering and it is ideal for use cases where you have components that may interact with DOM APIs, or may require the full lifecycle in order to fully test the component.
You can see that find returns using .debug().
After a few more attempts, I was able to get the test to work.
A shallow mount ended up being sufficient in this case even though I was interacting with input DOM element.
The simulate method used in the test script was changed to the following,
"countField.simulate('change',{
target: { name: "componentCount", value: 3 } });

Accent and deferred React's setState on input onChange

I'm creating a little utility where I need call a setState deferred to next tick fired by an input's onChange handler. Below a simple snippet showing the basic concept.
https://jsfiddle.net/samuelsimoes/q3p44sz1/
class MyComponent extends React.Component {
constructor () {
super(...arguments);
this.state = {};
}
onChange (value) {
setTimeout(v => {
this.setState({ name: v });
}.bind(this, value), 0);
}
render () {
return (
<div>
<input
type="text"
value={this.state.name}
onChange={evt => this.onChange(evt.target.value)} />
</div>
);
}
};
ReactDOM.render(
<MyComponent/>,
document.getElementById("app-container")
);
If you run this snippet in a browser on Mac OS and try to type some letter with an accent you get an awkward behavior different on each browser. On Chrome the accent only works for the first time, after the accent isn't applied anymore (take a look on the gif below). On Firefox, the accent and letter don't appear.
Do you guys have any clue about this?
p.s.: I tested this behavior on React 0.13, 0.14 and 15.0.2.
Basically you shouldn't defer the setState. React won't work properly in this situation.
Look: https://github.com/facebook/react/issues/6563
What is happening:
Let's suppose that you press the letter A.
When you trigger the onChange in the field, React processes all the state mutations.
After the state mutation process, React does the DOM diff to update the component and at this stage the state value for this field is an empty value, so React does a node.value = "".
On the next tick our deferred setState is triggered applying the letter A with the node.value = "A".
This behavior breaks the browsers on MacOS where they replace the accent on the "intermediate state" to a typed accent preventing user to type the accentuated character.
So, sadly there's no solution.

Categories

Resources