React slow with many controlled fields - javascript

I've been struggling with this for some time now. I'm creating a huge form and want to use controlled components. The only problem is, it's getting really slow, since my form is being rerendered with every keytroke I make.
Here is the Performance-Measurement for 10 keystrokes in one of my fields:
The React-Class (it's not complete yet):
class OrderEdit extends Component {
constructor(params) {
super(params);
this.state = {
activeTab: 1,
order: null,
customerValue: '',
warningTextCustomer: ''
};
this.loadOrder();
}
loadOrder = () => {
var me = this;
new ApiCall()
.withUrl('orders/edit/' + this.props.serialNumber)
.onSuccess((order) => {
me.setState({
order: order
});
})
.get();
};
validateCustomer = () => {
return;
if (!this.state.order.Customer) {
this.setState({
warningTextCustomer: 'Bitte gib einen Kunden an.'
});
} else {
this.setState({
warningTextCustomer: ''
});
}
};
onCustomerBlur = (event) => {
//this.validateCustomer();
};
onCustomerUpdateItem = (item) => {
var newOrder = this.state.order;
newOrder.Customer = item;
newOrder.Sender = item;
this.setState({
order: newOrder
}, () => this.validateCustomer);
};
onCustomerUpdateValue = (value) => {
this.setState({
customerValue: value
});
};
onSelectTab = (tabIndex) => {
this.setState({
activeTab: tabIndex
});
};
onUpdateDepartureDate = (date) => {
var newOrder = this.state.order;
newOrder.DepartureTimeFrom = date;
this.setState({order: newOrder})
};
render() {
if (!this.state.order) {
return (<Spinner style={{marginTop: '25%'}}/>);
}
return (
<PageContainer>
<PageTitle style={{marginBottom: 40}}
Title={"Auftrag " + this.state.order.SerialNumber + " bearbeiten"}/>
<Tabs activeTab={this.state.activeTab} onSelect={this.onSelectTab}>
<tab tabIndex={1} title="Allgemein">
<Section title="Allgemein">
<Row style={{marginBottom: 20}}>
<Col xs={12} md={6}>
<AutocompleteFieldCustomer
ref="customer"
title="Kunde"
focusAfterInit={true}
warningText={this.state.warningTextCustomer}
canCreate={true}
value={this.state.customerValue}
valueItem={this.state.order.Customer}
onBlur={this.onCustomerBlur}
onUpdateItem={this.onCustomerUpdateItem}
onUpdateValue={this.onCustomerUpdateValue}
titleElements={this.state.order.Customer.IsNewItem ?
<FieldTitleSuccess title="Kunde wird neu angelegt"/> : null}/>
<FieldNote text="Nicht existierende Kunden werden automatisch angelegt."/>
</Col>
</Row>
</Section>
<Section title="Sendung">
<Row style={{marginBottom: 20}}>
<Col xs={12} md={6}>
<Row style={{marginBottom: 20}}>
<Col xs={12} md={12}>
<AutocompleteFieldCustomer
title="Absender + Beladestation"/>
</Col>
</Row>
<Row style={{marginBottom: 20}}>
<Col xs={12} md={12}>
<LocationField />
</Col>
</Row>
<Row>
<Col xs={12} md={6}>
<DateField
title="Datum"/>
</Col>
<Col xs={12} md={6}>
<Row>
<Col xs={12} md={6}>
<TimeField title="Von"/>
</Col>
<Col xs={12} md={6}>
<TimeField title="Bis"/>
</Col>
</Row>
</Col>
</Row>
</Col>
<Col xs={12} md={6}>
<Row style={{marginBottom: 20}}>
<Col xs={12} md={12}>
<AutocompleteFieldCustomer
title="Empfänger + Entladestation"/>
</Col>
</Row>
<Row style={{marginBottom: 20}}>
<Col xs={12} md={12}>
<LocationField />
</Col>
</Row>
<Row>
<Col xs={12} md={6}>
<TextField title="Datum"/>
</Col>
<Col xs={12} md={6}>
<Row>
<Col xs={12} md={6}>
<TimeField title="Von"/>
</Col>
<Col xs={12} md={6}>
<TimeField title="Bis"/>
</Col>
</Row>
</Col>
</Row>
</Col>
</Row>
</Section>
<Section title="Fahrt">
<Row style={{marginBottom: 20}}>
<Col xs={12} md={6}>
<div style={{marginBottom: 20}}>
<AutocompleteFieldVehicle
title="Fahrzeug"
canCreate={true}/>
</div>
<div style={{marginBottom: 20}}>
<AutocompleteFieldUser
title="Fahrer"
canCreate={true}/>
</div>
</Col>
<Col xs={12} md={6}>
<AutocompleteFieldCustomer
title="Frachtführer"
canCreate={true}/>
</Col>
</Row>
</Section>
<Section title="Fakturierung">
<Row style={{marginBottom: 20}}>
<Col xs={12} md={6}>
<div style={{marginBottom: 20}}>
<AutocompleteFieldCustomer
title="Rechnungsempfänger Kunde"
canCreate={true}/>
</div>
<Row style={{marginBottom: 20}}>
<Col xs={12} md={6}>
<TextField title="Auftragspreis"/>
</Col>
<Col xs={12} md={6}>
<AutocompleteFieldTax
title="Steuerschlüssel"
canCreate={true}/>
</Col>
</Row>
</Col>
<Col xs={12} md={6}>
<div style={{marginBottom: 20}}>
<AutocompleteFieldCustomer
title="Gurtschriftempfänger Frachtführer"
canCreate={true}/>
</div>
<Row style={{marginBottom: 20}}>
<Col xs={12} md={6}>
<TextField title="Fahrtpreis"/>
</Col>
<Col xs={12} md={6}>
<AutocompleteFieldTax
title="Steuerschlüssel"
canCreate={true}/>
</Col>
</Row>
</Col>
</Row>
</Section>
</tab>
<tab tabIndex={2} title="Karte">Tab 3 content</tab>
</Tabs>
</PageContainer>
);
}
}
Does anyone know a solution for this? I've been reading a lot about Pure-Render-Mixin, shouldComponentUpdate, Immutable, but I'm not sure whether any of that would help me here or not.
thanks

Related

React Google Charts are minimazing for each switch tab change in tab component

I have built the following Tab component with one tab containing Google charts.
Tab component
return (
<Tabs
defaultActiveKey={activeKey}
items={items}
activeKey={activeKey}
onChange={onKeyChange}
/>
);
Tab with charts
return (
<div>
<Row style={rowStyle} gutter={gutter} justify="start">
<Col md={12} xs={24} style={colStyle}>
<Box title={configs.BarChart.title}>
<ContentHolder>
<GoogleChart {...configs.BarChart} chartEvents={chartEvents} />
</ContentHolder>
</Box>
</Col>
<Col md={12} xs={24} style={colStyle}>
<Box title={configs.lineChart.title}>
<ContentHolder>
<GoogleChart {...configs.lineChart} />
</ContentHolder>
</Box>
</Col>
</Row>
</div>
);
Initial view is ok but each time when I change the current tab and later switch to previous the area of chart is smallifying.
First render (OK)
Second render (Smallifying)

add dynamic useState

I see this link but didn't get any answer for my question
in my component , I have a two selectbox and one txtarea that owned Specified state(define by use state).
so on click add button this form create again and again,
my question is how to define new state dynamicly to set it for new selectbox that dynamicly created.
my select box use react-select and code of them is here :
<div className="mqContainer">
{[...Array(mqCount)].map((x, i) => (
<div key={i} className="newMqWrapper mt-4">
<Row className="mt-4">
<Col xs={3}>
<span>milestone</span>
</Col>
<Col xs={6}>
<Select
style={{ width: "100px !important" }}
defaultValue={mileStoneType}
onChange={setmileStoneType}
options={MileStoneTypeOption}
isMulti={true}
/>{" "}
</Col>
</Row>
<Row className="mt-4">
<Col xs={3}>
<span>question text</span>
</Col>
<Col xs={8}>
<Form.Group>
<Form.Control
placeholder="why so serious?"
className=" dirrtl"
as="textarea"
rows={3}
/>
</Form.Group>{" "}
</Col>
</Row>
<Row className="mt-4">
<Col xs={3}>
<span>answer type</span>
</Col>
<Col xs={6} className="mb-4">
<Select
defaultValue={mileStoneAnswerType}
onChange={setmileStoneAnswerType}
options={MqAnswerTypeOption}
/>{" "}
</Col>
</Row>
</div>
))}
<Row>
<Col xs={12} className=" mb-4 mt-4">
<Button
onClick={() => setMqCount(mqCount + 1)}
style={{ width: "100%" }}
variant="outline-secondary"
>
+
</Button>{" "}
</Col>
</Row>
</div>
I hope that I understand your problem correctly.
Regularly, you would create a Component in which you can call useState() separately. After that, you can render it inside your map().
I tried to reproduce your structure:
import { useState } from 'react'
const Form = () => {
const [ mqCount, setMqCount ] = useState(0)
return (
<div className='mqContainer'>
{[ ...Array(mqCount) ].map((x, i) => {
// TODO: pass your required props here
return <Item key={i} />
})}
<Row>
<Col className='mb-4 mt-4' xs={12}>
<Button
style={{ width: '100%' }}
variant='outline-secondary'
onClick={() => setMqCount(mqCount + 1)}
>
+
</Button>{' '}
</Col>
</Row>
</div>
)
}
const Item = ({ mileStoneType, MileStoneTypeOption, setmileStoneType }) => {
const [ yourState, setYourState ] = useState('Whatever you want')
// TODO: replace it with your own state
return (
<div key={i} className='newMqWrapper mt-4'>
<Row className='mt-4'>
<Col xs={3}>
<span>milestone</span>
</Col>
<Col xs={6}>
<Select
isMulti
defaultValue={mileStoneType}
options={MileStoneTypeOption}
style={{ width: '100px !important' }}
onChange={setmileStoneType}
/>{' '}
</Col>
</Row>
<Row className='mt-4'>
<Col xs={3}>
<span>question text</span>
</Col>
<Col xs={8}>
<Form.Group>
<Form.Control
as='textarea'
className=' dirrtl'
placeholder='why so serious?'
rows={3}
/>
</Form.Group>{' '}
</Col>
</Row>
<Row className='mt-4'>
<Col xs={3}>
<span>answer type</span>
</Col>
<Col className='mb-4' xs={6}>
<Select
defaultValue={mileStoneAnswerType}
options={MqAnswerTypeOption}
onChange={setmileStoneAnswerType}
/>{' '}
</Col>
</Row>
</div>
)
}

TypeError: Cannot read properties of undefined (reading 'image')

import React from 'react'
import { Link } from 'react-router-dom'
import { Row, Col, Image, ListGroup, Button, Card } from 'react-bootstrap'
import Rating from '../components/Rating'
import products from '../products'
function ProductScreen({ match }) {
const product = products.find((p) => p._id === match.params.id)
return (
<div>
<Link to='/' className='btn btn-light my-3'>Go Back</Link>
<Row>
<Col md={6}>
<Image src={product.image} alt={product.name} fluid />
</Col>
<Col md={3}>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating value={product.rating} text={'${product.numReviews} reviews'} color={'#f8e825'} ></Rating>
</ListGroup.Item>
<ListGroup.Item>
Price: ₹{product.price}
</ListGroup.Item>
<ListGroup.Item>
Description: {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<Row>
<Col>Price:</Col>
<Col>
<strong>{product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Status:</Col>
<Col>
{product.countInStok > 0 ? 'In Stock' : 'Out of Stock'}
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Button className='btn-block' type='button'> add to Cart </Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</div>
);
}
export default ProductScreen
enter image description here
product is undefined so you can't read any properties of it. to prevent happening error check the value of it before render:
if(!product)
return <></>
return (
<div>
<Link to='/' className='btn btn-light my-3'>Go Back</Link>
<Row>
<Col md={6}>
<Image src={product.image} alt={product.name} fluid />
</Col>
<Col md={3}>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating value={product.rating} text={'${product.numReviews} reviews'} color={'#f8e825'} ></Rating>
</ListGroup.Item>
<ListGroup.Item>
Price: ₹{product.price}
</ListGroup.Item>
<ListGroup.Item>
Description: {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<Row>
<Col>Price:</Col>
<Col>
<strong>{product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Status:</Col>
<Col>
{product.countInStok > 0 ? 'In Stock' : 'Out of Stock'}
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Button className='btn-block' type='button'> add to Cart </Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</div>);
As pointed in comment, your products variable has value undefined, hence your code fails.
Its always recommended and good practice to guard your code and avoid failures. There are multiple ways to guard yourself from these sitations. Optional chaining operator, or logical &&.
So you could use something like:
return products && <div>...</div>; or for some cases you would like to show loader if you fetch data:
return !products ? 'Loading...' : <div>...</div;. Or you can use products?.myProp1 on every place where your products variable appear. It can be cumbersome to repeat the same stuff and maybe you wish to guard/handle it differently.

Can't auto-size row height to image

I'm building a page with react-bootstrap and wanted to place an image as a background for one of the rows that I have in my grid. The height of the img is 1237.5px and it's placed in the Col Component. If I change the height explicitly to e.g. height: 25%, the image takes 25% of the height of the Row component but the Row component is still 1237.5px high.
I'd like Row component to have height: 30% of the desktop screen. It should be responsive and on mobile it should take the whole screen height.
function App() {
return (
<div className="App">
<UpperBar></UpperBar>
<Container fluid>
<Row >
<Col xs={12} md={12} >
<FirstBlock></FirstBlock>
</Col>
</Row>
<Row>
<Col xs={12} md={6}>1 of 2</Col>
<Col xs={12} md={6}>2 of 2</Col>
</Row>
<Row>
<Col xs={12} md={6}>1 of 2</Col>
<Col xs={12} md={6}>2 of 2</Col>
</Row>
</Container>
<Footer></Footer>
</div >
);
}
function FirstBlock() {
return (
<Image src={discolight} alt="first" style={{height: "25%", width: "100%"}}></Image>
);
}
enter image description here

Inline CSS Styles in React: Adding random variable

I'm trying to get the animation on .skill-logo to start playing at random times for each version.
React needs inline styles to be passed as an object. Which is what I have done here. Any ideas as to where to assign the randomness?
const Skills = () => {
let skillLogoStyle = {
animationDelay: Math.random() + 's',
};
return (
<Row className="skills-container">
<Col xs={12} mdOffset={2} md={2} lg={2}><img className="skill-logo" style={skillLogoStyle} src={html} alt="HTML5 Logo"/></Col>
<Col xs={12} md={2} lg={2}><img className="skill-logo" style={skillLogoStyle} src={css} alt="HTML5 Logo"/></Col>
<Col xs={12} md={2} lg={2}><img className="skill-logo" style={skillLogoStyle} src={js} alt="HTML5 Logo"/></Col>
<Col xs={12} md={2} lg={2}><img className="skill-logo" style={skillLogoStyle} src={react} alt="HTML5 Logo"/></Col>
<Col xs={12} md={2} lg={2}><img className="skill-logo" style={skillLogoStyle} src={node} alt="HTML5 Logo"/></Col>
</Row>
);
}
You could try creating a function that will return a random animationDelay and then call it for each element in render.
returnRandom = () => {
let random = Math.random()*10;
return {animationDelay: Math.random() + 's'}
and then in render set style to that function
<Col style = {returnRandom()}
Then each would have a different animation delay, which is what I am assuming you want.

Categories

Resources