Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 290dab0

Browse files
chore: refactor ParallaxProvider to function component (jscottsmith#230)
1 parent a9ebdd5 commit 290dab0

File tree

2 files changed

+84
-95
lines changed

2 files changed

+84
-95
lines changed
Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,49 @@
1-
import React, { Component } from 'react';
1+
import React, { PropsWithChildren,useEffect,useRef } from 'react';
22

33
import { ParallaxContext } from '../../context/ParallaxContext';
4-
import { ParallaxController,ScrollAxis } from 'parallax-controller';
4+
import { ScrollAxis } from 'parallax-controller';
55
import { ParallaxProviderProps } from './types';
66
import { createController } from './helpers';
77

8-
export class ParallaxProvider extends Component<ParallaxProviderProps, {}> {
9-
static defaultProps = {
10-
scrollAxis: ScrollAxis.vertical,
11-
};
12-
13-
controller: ParallaxController | null;
14-
15-
constructor(props: ParallaxProviderProps) {
16-
super(props);
17-
this.controller = createController({
18-
scrollAxis: props.scrollAxis,
8+
export function ParallaxProvider(
9+
props: PropsWithChildren<ParallaxProviderProps>
10+
) {
11+
const controller = useRef(
12+
createController({
13+
scrollAxis: props.scrollAxis || ScrollAxis.vertical,
1914
scrollContainer: props.scrollContainer,
2015
disabled: props.isDisabled,
21-
});
22-
}
16+
})
17+
);
2318

24-
componentDidUpdate(prevProps: ParallaxProviderProps) {
25-
if (
26-
prevProps.scrollContainer !== this.props.scrollContainer &&
27-
this.props.scrollContainer
28-
) {
29-
this.controller?.updateScrollContainer(this.props.scrollContainer);
19+
// update scroll container
20+
useEffect(() => {
21+
if (props.scrollContainer && controller.current) {
22+
controller.current.updateScrollContainer(props.scrollContainer);
3023
}
24+
}, [props.scrollContainer, controller.current]);
3125

32-
if (prevProps.isDisabled !== this.props.isDisabled) {
33-
if (this.props.isDisabled) {
34-
this.controller?.disableParallaxController();
35-
}
36-
if (!this.props.isDisabled) {
37-
this.controller?.enableParallaxController();
38-
}
26+
// disable/enable parallax
27+
useEffect(() => {
28+
if (props.isDisabled && controller.current) {
29+
controller.current.disableParallaxController();
3930
}
40-
}
41-
42-
componentWillUnmount() {
43-
// @ts-ignore
44-
this.controller = this.controller.destroy();
45-
}
46-
47-
render() {
48-
const { children } = this.props;
49-
return (
50-
// @ts-ignore
51-
<ParallaxContext.Provider value={this.controller}>
52-
{children}
53-
</ParallaxContext.Provider>
54-
);
55-
}
31+
if (!props.isDisabled && controller.current) {
32+
controller.current.enableParallaxController();
33+
}
34+
}, [props.isDisabled, controller.current]);
35+
36+
// remove the controller when unmounting
37+
useEffect(() => {
38+
return () => {
39+
controller?.current && controller?.current.destroy();
40+
controller.current = null;
41+
};
42+
}, []);
43+
44+
return (
45+
<ParallaxContext.Provider value={controller.current}>
46+
{props.children}
47+
</ParallaxContext.Provider>
48+
);
5649
}

‎src/components/ParallaxProvider/index.test.tsx‎

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -84,59 +84,53 @@ describe('A <ParallaxProvider>', () => {
8484
});
8585

8686
it('to destroy the controller when unmounting', () => {
87-
const node = document.createElement('div');
87+
let parallaxController: ParallaxController | null = null;
88+
const AddDestroySpy = () => {
89+
parallaxController = useParallaxController();
90+
if (parallaxController) {
91+
jest.spyOn(parallaxController, 'destroy');
92+
}
93+
return null;
94+
};
8895

89-
let instance;
90-
ReactDOM.render(
91-
<ParallaxProvider ref={(ref) => (instance = ref)}>
92-
<div />
93-
</ParallaxProvider>,
94-
node
96+
const screen = render(
97+
<ParallaxProvider>
98+
<AddDestroySpy />
99+
</ParallaxProvider>
95100
);
96101

97-
// @ts-ignore
98-
instance.controller.destroy = jest.fn();
99-
// @ts-ignore
100-
const spy = instance.controller.destroy;
101-
102-
ReactDOM.unmountComponentAtNode(node);
103-
104-
expect(spy).toBeCalled();
102+
screen.unmount();
103+
// @ts-expect-error
104+
expect(parallaxController?.destroy).toBeCalled();
105105
});
106106

107107
it('to update the scroll container when receiving a new container el', () => {
108-
const node = document.createElement('div');
109-
let instance;
110-
let providerInstance;
111-
112-
class StateChanger extends React.Component {
113-
state = { el: undefined };
114-
render() {
115-
return (
116-
<ParallaxProvider
117-
scrollContainer={this.state.el}
118-
ref={(ref) => (providerInstance = ref)}
119-
>
120-
<div />
121-
</ParallaxProvider>
122-
);
123-
}
124-
}
108+
let parallaxController: ParallaxController | null = null;
125109

126-
ReactDOM.render(<StateChanger ref={(ref) => (instance = ref)} />, node);
110+
const AddUpdateSpy = () => {
111+
parallaxController = useParallaxController();
112+
if (parallaxController) {
113+
jest.spyOn(parallaxController, 'updateScrollContainer');
114+
}
115+
return null;
116+
};
127117

128118
const el = document.createElement('div');
119+
const screen = render(
120+
<ParallaxProvider>
121+
<AddUpdateSpy />
122+
</ParallaxProvider>
123+
);
129124

130-
// @ts-ignore
131-
providerInstance.controller.updateScrollContainer = jest.fn();
132-
// @ts-ignore
133-
const spy = providerInstance.controller.updateScrollContainer;
134-
// @ts-ignore
135-
instance.setState({ el });
136-
137-
ReactDOM.unmountComponentAtNode(node);
125+
screen.rerender(
126+
<ParallaxProvider scrollContainer={el}>
127+
<AddUpdateSpy />
128+
</ParallaxProvider>
129+
);
138130

139-
expect(spy).toBeCalledWith(el);
131+
screen.unmount();
132+
// @ts-expect-error
133+
expect(parallaxController?.updateScrollContainer).toBeCalledWith(el);
140134
});
141135

142136
// NOTE: I think this test can be removed
@@ -150,10 +144,15 @@ describe('A <ParallaxProvider>', () => {
150144
const node2 = document.createElement('div');
151145

152146
const render = (node: HTMLDivElement) => {
153-
let instance;
147+
let instance: ParallaxController | null = null;
148+
const GetInstance = () => {
149+
instance = useParallaxController();
150+
return null;
151+
};
154152
ReactDOM.render(
155-
<ParallaxProvider ref={(ref) => (instance = ref)}>
156-
<div />
153+
// @ts-ignore
154+
<ParallaxProvider>
155+
<GetInstance />
157156
</ParallaxProvider>,
158157
node
159158
);
@@ -162,19 +161,16 @@ describe('A <ParallaxProvider>', () => {
162161

163162
// first instance mounted
164163
const instance1 = render(node1);
165-
// @ts-ignore
166-
expect(instance1.controller).toBeInstanceOf(ParallaxController);
164+
expect(instance1).toBeInstanceOf(ParallaxController);
167165

168166
// second instance mounted
169167
const instance2 = render(node2);
170-
// @ts-ignore
171-
expect(instance2.controller).toBeInstanceOf(ParallaxController);
168+
expect(instance2).toBeInstanceOf(ParallaxController);
172169

173170
// unmount first instance
174171
ReactDOM.unmountComponentAtNode(node1);
175172

176173
// this must still be defined
177-
// @ts-ignore
178-
expect(instance2.controller).toBeInstanceOf(ParallaxController);
174+
expect(instance2).toBeInstanceOf(ParallaxController);
179175
});
180176
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /