Skip to content

Commit 601e990

Browse files
authored
Merge pull request #162 from ZeroCho/intersection-observer
Update: next11 && image fallback
2 parents 35a59d7 + a0e9426 commit 601e990

File tree

12 files changed

+8380
-18407
lines changed

12 files changed

+8380
-18407
lines changed

intersection/front/components/AppLayout.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Link from 'next/link';
44
import { Menu, Input, Row, Col } from 'antd';
55
import styled from 'styled-components';
66
import { useSelector } from 'react-redux';
7-
import Router from 'next/router';
7+
import Router, { useRouter } from 'next/router';
88

99
import UserProfile from './UserProfile';
1010
import LoginForm from './LoginForm';
@@ -16,6 +16,7 @@ const SearchInput = styled(Input.Search)`
1616

1717
const AppLayout = ({ children }) => {
1818
const [searchInput, onChangeSearchInput] = useInput('');
19+
const router = useRouter();
1920
const { me } = useSelector((state) => state.user);
2021

2122
const onSearch = useCallback(() => {
@@ -24,14 +25,14 @@ const AppLayout = ({ children }) => {
2425

2526
return (
2627
<div>
27-
<Menu mode="horizontal">
28-
<Menu.Item>
28+
<Menu mode="horizontal" selectedKeys={[router.pathname]}>
29+
<Menu.Item key="/">
2930
<Link href="/"><a>노드버드</a></Link>
3031
</Menu.Item>
31-
<Menu.Item>
32+
<Menu.Item key="/profile">
3233
<Link href="/profile"><a>프로필</a></Link>
3334
</Menu.Item>
34-
<Menu.Item>
35+
<Menu.Item key="/search">
3536
<SearchInput
3637
enterButton
3738
value={searchInput}

intersection/front/components/PostImages.js

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,78 @@
1-
import React, { useCallback, useState } from 'react';
1+
import React, { useCallback, useState, useEffect, useRef } from 'react';
22
import PropTypes from 'prop-types';
33
import { PlusOutlined } from '@ant-design/icons';
44

55
import ImagesZoom from './ImagesZoom';
66

7+
function isImageValid(src) {
8+
return new Promise((resolve) => {
9+
const img = document.createElement('img');
10+
img.onerror = () => resolve(false);
11+
img.onload = () => resolve(true);
12+
img.src = src;
13+
});
14+
}
715
const PostImages = ({ images }) => {
816
const [showImagesZoom, setShowImagesZoom] = useState(false);
17+
const imgEl = useRef();
18+
19+
useEffect(
20+
() => {
21+
isImageValid(images[0].src).then((isValid) => {
22+
if (!isValid) {
23+
imgEl.current.remove();
24+
}
25+
});
26+
},
27+
[images[0].src],
28+
);
929

1030
const onZoom = useCallback(() => {
1131
setShowImagesZoom(true);
1232
}, []);
1333
const onClose = useCallback(() => {
1434
setShowImagesZoom(false);
1535
}, []);
36+
1637
const onError = useCallback((e) => {
17-
e.target.src = e.target.src.replace('/thumb/', '/original/');
38+
console.dir(e.target);
39+
e.target.previousSibling.remove();
40+
// e.target.src = e.target.currentSrc.replace('/thumb/', '/original/');
1841
}, []);
1942

2043
if (images.length === 1) {
2144
return (
2245
<>
23-
<img role="presentation" src={`${images[0].src}`} alt={images[0].src} onClick={onZoom} onError={onError} />
46+
<picture>
47+
<source ref={imgEl} srcSet={`${images[0].src}`} />
48+
<img role="presentation" onClick={onZoom} src={`${images[0].src.replace('/thumb/', '/original/')}`} alt={images[0].src} style={{ maxWidth: '100%', display: 'inline-block' }} />
49+
</picture>
2450
{showImagesZoom && <ImagesZoom images={images} onClose={onClose} />}
2551
</>
2652
);
2753
}
2854
if (images.length === 2) {
2955
return (
3056
<>
31-
<img role="presentation" style={{ width: '50%', display: 'inline-block' }} src={`${images[0].src}`} alt={images[0].src} onClick={onZoom} onError={onError} />
32-
<img role="presentation" style={{ width: '50%', display: 'inline-block' }} src={`${images[1].src}`} alt={images[1].src} onClick={onZoom} onError={onError} />
57+
<picture style={{ width: '50%', display: 'inline-block' }}>
58+
<source ref={imgEl} srcSet={`${images[0].src}`} />
59+
<img role="presentation" onClick={onZoom} src={`${images[0].src.replace('/thumb/', '/original/')}`} alt={images[0].src} style={{ maxWidth: '100%', display: 'inline-block' }} />
60+
</picture>
61+
<picture style={{ width: '50%', display: 'inline-block' }}>
62+
<source ref={imgEl} srcSet={`${images[1].src}`} />
63+
<img role="presentation" onClick={onZoom} src={`${images[1].src.replace('/thumb/', '/original/')}`} alt={images[0].src} style={{ maxWidth: '100%', display: 'inline-block' }} />
64+
</picture>
3365
{showImagesZoom && <ImagesZoom images={images} onClose={onClose} />}
3466
</>
3567
);
3668
}
3769
return (
3870
<>
3971
<div>
40-
<img role="presentation" style={{ width: '50%' }} src={`${images[0].src}`} alt={images[0].src} onClick={onZoom} onError={onError} />
72+
<picture style={{ width: '50%' }} onError={onError}>
73+
<source ref={imgEl} srcSet={`${images[0].src}`} />
74+
<img role="presentation" onClick={onZoom} src={`${images[0].src.replace('/thumb/', '/original/')}`} alt={images[0].src} style={{ maxWidth: '50%' }} />
75+
</picture>
4176
<div
4277
role="presentation"
4378
style={{ display: 'inline-block', width: '50%', textAlign: 'center', verticalAlign: 'middle' }}
@@ -55,7 +90,7 @@ const PostImages = ({ images }) => {
5590
};
5691

5792
PostImages.propTypes = {
58-
images: PropTypes.arrayOf(PropTypes.object),
93+
images: PropTypes.arrayOf(PropTypes.object).isRequired,
5994
};
6095

6196
export default PostImages;

intersection/front/next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module.exports = withBundleAnalyzer({
99
return {
1010
...config,
1111
mode: prod ? 'production' : 'development',
12-
devtool: prod ? 'hidden-source-map' : 'eval',
12+
devtool: prod ? 'hidden-source-map' : 'eval-source-map',
1313
plugins: [
1414
...config.plugins,
1515
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /^\.\/ko$/),

0 commit comments

Comments
 (0)