Skip to content

Commit 8446d67

Browse files
author
rizovs
committed
refactor
1 parent d7535f5 commit 8446d67

File tree

3 files changed

+40
-37
lines changed

3 files changed

+40
-37
lines changed

src/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function App() {
1717
</Link>
1818
<span>
1919
Panels scroll into view if not fully visible when toggled.
20-
Using <pre>useImperativeMethods</pre>, <pre>useRef</pre> and <pre>useMemo</pre>.
20+
Using <pre>useImperativeMethods</pre>, <pre>useRef</pre>.
2121
</span>
2222
</div>
2323
<div className="item">

src/components/accordion/Accordion.js

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import React, { useRef, createRef, useMemo, useImperativeMethods, useState, useEffect } from 'react';
1+
import React, { useRef, createRef, forwardRef, useImperativeMethods, useState, useEffect } from 'react';
22
import scrollIntoView from 'scroll-into-view-if-needed';
3-
import FoobarIpsum from 'foobar-ipsum';
43

54
function useAccordion(panelsCount) {
65
const [currentIndex, setCurrentIndex] = useState();
@@ -15,14 +14,14 @@ function useAccordion(panelsCount) {
1514
refs[i] = createRef();
1615
}
1716
setRefs(refs);
18-
}, []);
17+
}, []); // run once
1918

2019
useEffect(() => {
2120
// Scroll current accordion panel into view
2221
if (currentIndex !== undefined) {
2322
refs[currentIndex].current.scrollIntoView();
2423
}
25-
}, [currentIndex]);
24+
}, [currentIndex]); // Run every time current index changes
2625

2726
function setCurrent(newIndex) {
2827
setCurrentIndex(currentIndex === newIndex ? undefined : newIndex);
@@ -31,42 +30,32 @@ function useAccordion(panelsCount) {
3130
return [currentIndex, setCurrent, refs];
3231
}
3332

34-
const AccordionPanel = React.forwardRef((props, ref) => {
35-
const containerRef = useRef();
36-
37-
// We don't want to generate random text every time this component renders
38-
const randomText = useMemo(() => generateRandomText(), []);
39-
40-
useImperativeMethods(ref, () => ({
41-
scrollIntoView: () => {
42-
scrollIntoView(containerRef.current, { block: 'nearest', scrollMode: 'if-needed' });
43-
}
44-
}));
45-
46-
return <div onClick={props.onClick} ref={containerRef}>
47-
<div className="accordion-label">{props.label}</div>
48-
{props.isOpen &&
49-
<div>{randomText}</div>}
50-
</div>;
51-
});
33+
// We don't want to re-render this component every time it receives new props
34+
// We also pass second parameter to this function where we implement our own comparison
35+
const AccordionPanel = React.memo(
36+
forwardRef((props, ref) => {
37+
const containerRef = useRef();
38+
39+
useImperativeMethods(ref, () => ({
40+
scrollIntoView: () => {
41+
scrollIntoView(containerRef.current, { block: 'nearest', scrollMode: 'if-needed' });
42+
}
43+
}));
44+
45+
return <div onClick={props.onClick} ref={containerRef}>
46+
<div className="accordion-label">{props.label}</div>
47+
{props.isOpen &&
48+
<div>{props.content}</div>}
49+
</div>;
50+
}),
51+
// practically shouldComponentUpdate, but reversed
52+
(prevProps, nextProps) => prevProps.isOpen === nextProps.isOpen
53+
);
5254

5355
function Accordion(props) {
5456
return <div>{props.children}</div>;
5557
}
5658

57-
function generateRandomNumber(max) {
58-
return Math.floor(Math.random() * Math.floor(max));
59-
}
60-
61-
function generateRandomText() {
62-
return new FoobarIpsum({
63-
size: {
64-
sentence: generateRandomNumber(100),
65-
paragraph: generateRandomNumber(10)
66-
}
67-
}).paragraph();
68-
}
69-
7059
export {
7160
useAccordion,
7261
Accordion,

src/components/accordion/index.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22

33
import { Accordion, AccordionPanel, useAccordion } from './Accordion';
4+
import FoobarIpsum from "foobar-ipsum";
45

56
function AccordionScreen() {
67
const panels = [...Array(100).keys()].map(e => `Panel number ${e}`);
@@ -11,14 +12,27 @@ function AccordionScreen() {
1112
{panels.map((panel, index) => (
1213
<AccordionPanel
1314
ref={refs && refs[index]}
14-
index={index}
1515
key={index}
1616
label={panel}
17+
content={generateRandomText()}
1718
isOpen={currentIndex === index}
1819
onClick={() => setCurrent(index)}
1920
/>
2021
))}
2122
</Accordion>;
2223
}
2324

25+
function generateRandomNumber(max) {
26+
return Math.floor(Math.random() * Math.floor(max));
27+
}
28+
29+
function generateRandomText() {
30+
return new FoobarIpsum({
31+
size: {
32+
sentence: generateRandomNumber(100),
33+
paragraph: generateRandomNumber(10)
34+
}
35+
}).paragraph();
36+
}
37+
2438
export default AccordionScreen;

0 commit comments

Comments
 (0)