web: components: Fix re-rendering of TextInput

This commit is contained in:
Alexey Safronov 2019-09-17 14:07:35 +03:00
parent 428fd7f075
commit f183b2f55d
3 changed files with 54 additions and 15 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useState, useCallback } from 'react';
import { Collapse, Container, Row, Col } from 'reactstrap'; import { Collapse, Container, Row, Col } from 'reactstrap';
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import TextInput from '../text-input'; import TextInput from '../text-input';
@ -11,7 +11,7 @@ const LoginForm = props => {
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [passwordValid, setPasswordValid] = useState(true); const [passwordValid, setPasswordValid] = useState(true);
const validateAndSubmit = (event) => { const validateAndSubmit = useCallback((event) => {
if (!login.trim()) if (!login.trim())
setLoginValid(false); setLoginValid(false);
@ -22,7 +22,17 @@ const LoginForm = props => {
return onSubmit(event, { login, password }); return onSubmit(event, { login, password });
return false; return false;
}; }, []);
const onLoginChange = useCallback(event => {
setLogin(event.target.value);
setLoginValid(true);
}, [])
const onPasswordChange = useCallback(event => {
setPassword(event.target.value);
setPasswordValid(true);
}, []);
return ( return (
<Container> <Container>
@ -38,10 +48,7 @@ const LoginForm = props => {
scale={true} scale={true}
isAutoFocussed={true} isAutoFocussed={true}
tabIndex={1} tabIndex={1}
onChange={event => { onChange={onLoginChange} />
setLogin(event.target.value);
setLoginValid(true);
}} />
</Col> </Col>
</Row> </Row>
<Row style={{ margin: "23px 0 0" }}> <Row style={{ margin: "23px 0 0" }}>
@ -56,10 +63,8 @@ const LoginForm = props => {
size='huge' size='huge'
scale={true} scale={true}
tabIndex={2} tabIndex={2}
onChange={event => { onChange={onPasswordChange}
setPassword(event.target.value); />
setPasswordValid(true);
}} />
</Col> </Col>
</Row> </Row>
<Row style={{ margin: "23px 0 0" }}> <Row style={{ margin: "23px 0 0" }}>

View File

@ -3,9 +3,14 @@ import PropTypes from 'prop-types'
import styled from 'styled-components'; import styled from 'styled-components';
import commonInputStyle from '../text-input/common-input-styles'; import commonInputStyle from '../text-input/common-input-styles';
import MaskedInput from 'react-text-mask' import MaskedInput from 'react-text-mask'
import isEqual from "lodash/isEqual";
/* eslint-disable no-unused-vars */
/* eslint-disable react/prop-types */
const Input = ({ isAutoFocussed, isDisabled, isReadOnly, hasError, hasWarning, scale, withBorder, keepCharPositions, ...props }) => const Input = ({ isAutoFocussed, isDisabled, isReadOnly, hasError, hasWarning, scale, withBorder, keepCharPositions, ...props }) =>
(props.mask != null) ? <MaskedInput keepCharPositions {...props}/> : <input {...props}/>; (props.mask != null) ? <MaskedInput keepCharPositions {...props}/> : <input {...props}/>;
/* eslint-enable react/prop-types */
/* eslint-enable no-unused-vars */
const StyledInput = styled(Input).attrs((props) => ({ const StyledInput = styled(Input).attrs((props) => ({
id: props.id, id: props.id,
@ -75,9 +80,15 @@ const StyledInput = styled(Input).attrs((props) => ({
${props => !props.withBorder && `border: none;`} ${props => !props.withBorder && `border: none;`}
`; `;
const TextInput = props => { class TextInput extends React.Component {
//console.log("TextInput render"); shouldComponentUpdate(nextProps) {
return (<StyledInput {...props} />); return !isEqual(this.props, nextProps);
}
render() {
// console.log(`TextInput render id=${this.props.id}`);
return (<StyledInput {...this.props} />);
}
} }
TextInput.propTypes = { TextInput.propTypes = {

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mount, shallow } from 'enzyme';
import TextInput from '.'; import TextInput from '.';
describe('<TextInput />', () => { describe('<TextInput />', () => {
@ -10,4 +10,27 @@ describe('<TextInput />', () => {
expect(wrapper).toExist(); expect(wrapper).toExist();
}); });
it('not re-render test', () => {
const onChange= event => alert(event.target.value);
const wrapper = shallow(<TextInput value="text" onChange={onChange} />).instance();
const shouldUpdate = wrapper.shouldComponentUpdate(wrapper.props);
expect(shouldUpdate).toBe(false);
});
it('re-render test by value', () => {
const onChange= event => alert(event.target.value);
const wrapper = shallow(<TextInput value="text" onChange={onChange} />).instance();
const shouldUpdate = wrapper.shouldComponentUpdate({
...wrapper.props,
value: "another text"
});
expect(shouldUpdate).toBe(true);
});
}); });