Skip to content

Commit 69f329b

Browse files
authored
revert(avatar): Move Avatar back to non-hook implementation (#1186)
1 parent 48d711e commit 69f329b

File tree

2 files changed

+55
-56
lines changed

2 files changed

+55
-56
lines changed

src/components/avatar/Avatar.js

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @flow
2-
import React, { useState, useEffect } from 'react';
2+
import * as React from 'react';
33
import classNames from 'classnames';
44
import AvatarImage from './AvatarImage';
55
import AvatarInitials from './AvatarInitials';
@@ -30,36 +30,50 @@ type Props = {
3030
size?: $Keys<typeof SIZES>,
3131
};
3232

33-
function Avatar({ avatarUrl, className, name, id, size = '' }: Props) {
34-
const [hasImageErrored, setHasImageErrored] = useState(false);
35-
const classes = classNames(['avatar', className, { [`avatar--${size}`]: SIZES[size] }]);
33+
type State = {
34+
/** boolean to determine if image did not load correctly */
35+
hasImageErrored: boolean,
36+
};
3637

37-
// Reset hasImageErrored state when avatarUrl changes
38-
useEffect(() => {
39-
setHasImageErrored(false);
40-
}, [avatarUrl]);
38+
class Avatar extends React.PureComponent<Props, State> {
39+
state = {
40+
hasImageErrored: false,
41+
};
4142

42-
let avatar;
43-
if (avatarUrl && !hasImageErrored) {
44-
avatar = (
45-
<AvatarImage
46-
onError={() => {
47-
setHasImageErrored(true);
48-
}}
49-
url={avatarUrl}
50-
/>
51-
);
52-
} else if (name) {
53-
avatar = <AvatarInitials id={id} name={name} />;
54-
} else {
55-
avatar = <UnknownUserAvatar className="avatar-icon" />;
43+
componentWillReceiveProps(nextProps: Props) {
44+
if (this.state.hasImageErrored && this.props.avatarUrl !== nextProps.avatarUrl) {
45+
this.setState({
46+
hasImageErrored: false,
47+
});
48+
}
5649
}
5750

58-
return (
59-
<span className={classes} role="presentation">
60-
{avatar}
61-
</span>
62-
);
51+
onImageError = () => {
52+
this.setState({
53+
hasImageErrored: true,
54+
});
55+
};
56+
57+
render() {
58+
const { avatarUrl, className, name, id, size = '' }: Props = this.props;
59+
const { hasImageErrored }: State = this.state;
60+
const classes = classNames(['avatar', className, { [`avatar--${size}`]: SIZES[size] }]);
61+
62+
let avatar;
63+
if (avatarUrl && !hasImageErrored) {
64+
avatar = <AvatarImage onError={this.onImageError} url={avatarUrl} />;
65+
} else if (name) {
66+
avatar = <AvatarInitials id={id} name={name} />;
67+
} else {
68+
avatar = <UnknownUserAvatar className="avatar-icon" />;
69+
}
70+
71+
return (
72+
<span className={classes} role="presentation">
73+
{avatar}
74+
</span>
75+
);
76+
}
6377
}
6478

6579
export default Avatar;

src/components/avatar/__tests__/Avatar-test.js

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import React from 'react';
2-
import { act } from 'react-dom/test-utils';
32

43
import Avatar from '../Avatar';
54

6-
function MockAvatarImage() {
7-
return <div className="avatar-image" />;
8-
}
9-
10-
jest.mock('../AvatarImage', () => MockAvatarImage);
11-
125
const testDataURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
136

147
describe('components/avatar/Avatar', () => {
@@ -29,7 +22,7 @@ describe('components/avatar/Avatar', () => {
2922

3023
test('should render an AvatarImage when avatarUrl is passed in', () => {
3124
const wrapper = shallow(<Avatar avatarUrl={testDataURI} />);
32-
const avatarImage = wrapper.find(MockAvatarImage);
25+
const avatarImage = wrapper.find('AvatarImage');
3326
expect(avatarImage.length).toEqual(1);
3427
expect(avatarImage.prop('url')).toEqual(testDataURI);
3528
});
@@ -58,9 +51,10 @@ describe('components/avatar/Avatar', () => {
5851

5952
test('should fall back to AvatarInitials when there is an error in AvatarImage', () => {
6053
const wrapper = shallow(<Avatar avatarUrl="http://foo.bar/baz123_invalid" id="1" name="hello world" />);
61-
const avatarImage = wrapper.find(MockAvatarImage);
62-
avatarImage.prop('onError')();
6354

55+
wrapper.instance().onImageError();
56+
expect(wrapper.state('hasImageErrored')).toEqual(true);
57+
wrapper.update();
6458
const avatarInitials = wrapper.find('AvatarInitials');
6559
expect(avatarInitials.length).toEqual(1);
6660
});
@@ -72,27 +66,18 @@ describe('components/avatar/Avatar', () => {
7266
avatarUrl: 'http://foo.bar/baz123_invalid',
7367
};
7468

75-
let wrapper;
76-
act(() => {
77-
wrapper = mount(<Avatar {...props} />);
78-
});
79-
expect(wrapper.find(MockAvatarImage).length).toEqual(1);
69+
const wrapper = shallow(<Avatar {...props} />);
8070

81-
act(() => {
82-
const avatarImage = wrapper.find(MockAvatarImage);
83-
avatarImage.prop('onError')();
84-
});
85-
wrapper.update();
86-
expect(wrapper.find(MockAvatarImage).length).toEqual(0);
87-
expect(wrapper.find('AvatarInitials').length).toEqual(1);
88-
89-
act(() => {
90-
wrapper.setProps({
91-
...props,
92-
avatarUrl: 'http://foo.bar/baz123_invalid_new',
93-
});
71+
wrapper.instance().onImageError();
72+
expect(wrapper.state('hasImageErrored')).toEqual(true);
73+
74+
wrapper.setProps({
75+
...props,
76+
avatarUrl: 'http://foo.bar/baz123_invalid_new',
9477
});
9578
wrapper.update();
96-
expect(wrapper.find(MockAvatarImage).length).toEqual(1);
79+
80+
expect(wrapper.state('hasImageErrored')).toEqual(false);
81+
expect(wrapper.find('AvatarImage').length).toEqual(1);
9782
});
9883
});

0 commit comments

Comments
 (0)