Performance Issue On Render In ReactJS - javascript

From what I'm reading, desired practice for working with form elements and state update is following:
onChange = (event) => {
this.setState({
name:event.target.value
})
}
where above is event handler for a input field:
<input
type="text"
onChange={this.onChange}
value={this.state.name}
/>
And this is how we keep state updated, and also input field itself.
Now if we put a console.log(new Date()) inside render function, we can observe that render is called on each key press in input field.
My question is, can this cause a performance issue, actually if there are known cases when this can cause performance issue?
Also, isn't there any better way, this updating-state-re-rendering doesn't seem to be most efficient?
Edit 1: Imagine complex form control, lots of complex form items that can be further more complex controls,... So this input is inside of this complex component that is timely to render. Now, can you expect(did ever happened to you), that re-rendering on state update(while typing) to cause performance issue (visible lag).

This is how React is built. See official doc.
You can use web inspector and type to check what’s being re-rendered and that’s only the text input box.
Yes it gets called every time you type, but only what’s being changed actually re-renders.

Related

React Handle multiple forms within a parent component

I have a page with dynamic tabs and each of them have a form input. There is a common Submit for each of these forms. As of now, I have a separate component for each of the forms and each of them have multiple user inputs.
<div id="#parentComponent">
{myForm1 && <div><MyForm1 {...props}/></div>}
{myForm2 && <MyForm2 {...props} /></div>}
<div>
<input type="submit">
Now, my question is on Submit (common and in the parent component), I want to be able to access each of the form input values. But as of now, my inactive tab/component gets destroyed and only the active tab/component is there in the DOM.
What is the best way to handle this? Also should there be any preference to controlled/uncontrolled components to handle this use case ?
As of now, I am using the uncontrolled form for these form inputs (using the useformcontext)
I would keep the state in a higher order component, and update it by any change withing the forms.
I would pass down a setFormsData function to every form, and add their data on every change, keeping the old state, like this:
const handleOnChange = value => setFormsData(oldFormData => {...oldFormData, ...value})
You can also use a redux store if you wish.

REACT.JS - how to update multiple children on parents state change by one of children

I am struggling for a few days with React, and all the tutorials saying how magnificent it is make me feel that somebody is tricking me :) Learning curve especially while i need to comunicate children-parent-children is so annoying! Anyways...
Consider such a situation:
I have multiple buttons. Each button has its own type. There may be mutiple buttons with one type making a group. Whole idea is to have buttons enabling other buttons, and disabling other ones.
I provide pen to see working example, however imagine i have buttons of types:
settingsOn - it enables all the buttons of type settings
settings - disabled at the begining, enabled after clicking settingsOn button
next - it enables all the buttons of type answer
answers - like settings, enabled after clicking next button.
Normal button looks like this:
<MyButton name='next' type="next" check={() => this.checker("next")} toggle={this.toggler.bind(this)} />
Parent send toggle function and check function with parameters to child.
Only settingOn and next are enabled at beginining. It is made by App.state.next set to true and App.state.answers to false. If App.state.answers is false all the components of type answers are disabled.
Now, everything seems to be working here however one last thing is not:
If i press button "next" it checks what is parent's state.answer and sets it to true (check console log in my pen for confirmation). However changing parent's this.state.answer to true doesnt rerender components of type answer.
To be honest i wanted to make it less messy and learn React, but it seems i could do it via jQuery in one hour a few days ago :/ Is there a good solution for my problem? Should i come back to jQuery and forget React? Or i am one step from solving the problem?
Please help!
Link to codepen
Here's a couple of things I noticed on your codepen that stood out as possible issues.
onClicked(){
this.setState = { answer: this.props.toggle("answer") };
// should be
this.setState({
answer: this.props.toggle("answer)
});
}
Another observation is on componentDidMount you're setting a default state with this.setState({ answer: false, isActive: this.props.check("next") }), I would move these default states to the constructor() as it'd avoid a rerender.
I'm not exactly sure if this is an anti-pattern or not, but I'd avoid setting/getting state like
this.setState({
[type]: !this.state[type]
// instead use
type: !this.state.type
})
Finally I think I was able to get a working component of what you were asking, see this codepen.io. Hopefully this helps, happy coding!

Get data from dynamic form in React

I have some troubles getting data from a form in react. The form itself is dynamic, meaning that some of my fields aren't always there, but only rendered in specific cases.
When attaching these its hard to anticipate how the state of the container should look. And also which handleChange functions should be there. The components in my form are 2 levels deep at least, so the component is in itself rendering the final input component to the DOM.
Did some looking and found that people have been using refs, but there is a lot of negative opinions about this approach. And it does seem kinda... Fiddly.
Question:
How could you go about getting all the data from a form when its dynamic?
The setup:
<Form onSubmit={this.acceptOffer.bind(this)}>
<MainProductContainer offer={this.state.offer}/>
<RequirementsContainer requirements={this.state.offer.requirements}/>
<Segment basic textAlign='center'>
<Button
type='submit'
content='Send'
primary
loading={this.state.accept_state == 'pending'}>
</Button>
</Segment>
.
acceptOffer(event) {
//This is where I want to get all the data from the form
}
Here you can find how to do it: React Native how to pass this.setState change to parent

React render, change radio button programmatically

I was creating a Dropdown component for React. Inside the dropdown, I have a form of radio group buttons.
<DropdownButton />
<DropdownForm />
In the DropdownButton, I have an state to know if it is open or not. Depends on that, DropdownForm it's hidden or not (using display: none).
The use case is: User selects a radio button, click apply and something happen. However, if user selects some radio button, and mouse out the dropdown (without clicking the apply button), the one that is selected should be the one that I get from the store.
Something like:
render: function () {
...
if(store.getSomeParam() != this.state.someParam && !this.props.isOpen){
someParam = store.getSomeParam()
}
Then the radio buttons are like:
<input checked={someParam == "something"} ... />
It doesn't really work. It re-renders but it doesn't change the button that is checked. I also tried with refs:
this.refs.myInput.getDOMNode().checked = true
But still nothing. Is this a correct behaviour?
The only solution I found so far is not using a css hiding class (display: none). So what I do is that the DropdownButton renders the DropdownForm depending on if it's open or not (so if you close it, you are forcing DropdownForm to unmount). Then when opening again, it is taking the values from the store (getInitialState) and it shows the correct radio button selected. But, I am not sure if this is the best solution and if there is any drawback in unmounting the component instead of just css hiding it.
This probably has nothing to do with React at all.
Most browsers don't validate the value of the checked attribute, but merely if it is there or not: http://jsfiddle.net/7jzm7gvw/
Just set the checked attribute to either true or null:
<input checked={someParam == "something" ? true: null} ... />
TL;DR: You must use the componentDidMount lifecycle method, not render, to work with the rendered dom nodes directly.
I was struggling with this as well, and after doing some online research I figured I might as well look into it for myself. Here's what I came up with:
Use the componentDidMount lifecycle method and update whatever you need to in there. Here's a Pen I used to prototype this, and I think it looks okay: http://codepen.io/gholts/pen/GpWzdb
You could drop this in pretty easily to what your'e working on by just putting a componentDidMount method on your object and doing it there. I used document.getElementById but you could definitely use jQuery or whatever else you wanted in there, as once the component has mounted it's available to DOM selectors.
I'm using this now to update 20 radio button groups (so it has to check a prop for three different states and update accordingly) and it loads instantly.
Hope it helps! I used the ES6 class syntax in my Pen, you should check it out if you have some time to refactor :) It's fun.
EDIT: So I figured it out, I'm a dummy. You don't need to do the whole document.getElementById business that I was doing. Just use your this.refs.whichever.getDOMNode().checked = true and it'll work, so long as you do it in componentDidMount. It works there because there is an actual DOM element on the page at that point.

JSF custom component losing input focus on ajax update

I'm writing an autocomplete custom component as a learning exercise with JSF
2.1.3. The idea (which is probably pretty familiar) is to enter some text into
and input component and present a list box with matching values. The idea is
to have a keyup javascript event on the input which calls jsf.ajax.request()
to update the component. So far I've got a component which I can include like
this:
<mycc:autocomplete id="myauto" searchMethod="#{bean.doSearch}"/>
This renders html like this:
<span id="myauto">
<input type="text" id="myauto_input" name="myauto_input"
onkeyup="com.myco.ajaxRequest(this, event)"/>
<select id="myauto_listbox" name="myauto_listbox">
<option value="1st">First</option>
<option value="2nd">Second</option>
</select>
</span>
The com.myco.ajaxRequest() javascript function (keyup) does this:
jsf.ajax.request(comp, null, {
execute: 'myauto',
render: 'myauto'
});
So because I want to rebuild and rerender the listbox with the suggestions
list, I'm re-rendering the custom component 'myauto'. By specifying execute:
'myauto' the decode() method executes and I can get the input value. By
specifying render: 'myauto' the encode...() methods execute to regenerate
the html.
This is all fine but because I'm rendering the parent of the myauto_input
component I lose input focus every time the keyup event fires.
If I specify something like render: 'myauto_listbox' (I only really want to
rerender the listbox after all) the problem is that the encode...() methods
don't execute, because they're for the custom component as a whole, not just
the listbox. And it would be in one of the encode...() methods that I rebuild
the listbox containing the suggestions.
The component extends UIInput and I generate markup in a separate renderer
(componentFamily = "javax.faces.Input") in the encodeEnd() method (so this
always runs after any supplied converter - not yet implemented). I suppose
that forcing focus from javascript is a horrible hack and to be avoided.
I'm a bit unsure where to go with this, but I suspect that what I'm seeing
indicates that I'm approaching this in the wrong way somehow. If anyone
would be good enough to point me in the right direction I'd greatly appreciate
it.
I've spent some time looking into this and the general issue of losing focus after
an ajax update is fairly common and is described in Jim Driscoll's blog (see
'Keeping Focus').
In the case of my custom component I (think I...) have to update the custom component
itself which is the parent of the input, so I'm going to lose focus as a result of the
ajax update, and that's just the way it is. As such I've looked at what needs to be
done to restore focus, and it seems that in my renderer encode I simply have to
forcibly restore focus to the input, but only when responding to the POST sent from the onkeyup event by jsf.ajax.request. I use jQuery and just calling .focus() isn't
enough because you also have to get the cursor position to the end of any existing
input. This code below seems to work ok:
<script>
jQuery(function($){var cid='#myauto_input';$(cid).focus().focus().click();$(cid).val($(cid).val());});
</script>
(note: .focus().focus().click() required for IE8, just .focus() works on chrome...)
So it looks like the horrible hack has saved the day. I did wonder if there would be
any difference if I used the jQuery ajax routines rather than the jsf ajax library but
I don't suppose it would make any difference.

Categories

Resources