main
js 145 lines 4 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @emails react-core
8 */
9
10 'use strict';
11
12 let act;
13 let assertConsoleErrorDev;
14 let React;
15 let ReactDOMClient;
16
17 describe('ReactPureComponent', () => {
18 beforeEach(() => {
19 ({act, assertConsoleErrorDev} = require('internal-test-utils'));
20
21 React = require('react');
22 ReactDOMClient = require('react-dom/client');
23 });
24
25 it('should render', async () => {
26 let renders = 0;
27 class Component extends React.PureComponent {
28 constructor() {
29 super();
30 this.state = {type: 'mushrooms'};
31 }
32 render() {
33 renders++;
34 return <div>{this.props.text[0]}</div>;
35 }
36 }
37
38 const container = document.createElement('div');
39 const root = ReactDOMClient.createRoot(container);
40 let text;
41 const componentRef = React.createRef();
42
43 text = ['porcini'];
44 await act(() => {
45 root.render(<Component ref={componentRef} text={text} />);
46 });
47 expect(container.textContent).toBe('porcini');
48 expect(renders).toBe(1);
49
50 text = ['morel'];
51 await act(() => {
52 root.render(<Component ref={componentRef} text={text} />);
53 });
54 expect(container.textContent).toBe('morel');
55 expect(renders).toBe(2);
56
57 text[0] = 'portobello';
58 await act(() => {
59 root.render(<Component ref={componentRef} text={text} />);
60 });
61 expect(container.textContent).toBe('morel');
62 expect(renders).toBe(2);
63
64 // Setting state without changing it doesn't cause a rerender.
65 await act(() => {
66 componentRef.current.setState({type: 'mushrooms'});
67 });
68 expect(container.textContent).toBe('morel');
69 expect(renders).toBe(2);
70
71 // But changing state does.
72 await act(() => {
73 componentRef.current.setState({type: 'portobello mushrooms'});
74 });
75 expect(container.textContent).toBe('portobello');
76 expect(renders).toBe(3);
77 });
78
79 it('can override shouldComponentUpdate', async () => {
80 let renders = 0;
81 class Component extends React.PureComponent {
82 render() {
83 renders++;
84 return <div />;
85 }
86 shouldComponentUpdate() {
87 return true;
88 }
89 }
90
91 const container = document.createElement('div');
92 const root = ReactDOMClient.createRoot(container);
93 await act(() => {
94 root.render(<Component />);
95 });
96 assertConsoleErrorDev([
97 'Component has a method called shouldComponentUpdate(). ' +
98 'shouldComponentUpdate should not be used when extending React.PureComponent. ' +
99 'Please extend React.Component if shouldComponentUpdate is used.\n' +
100 ' in Component (at **)',
101 ]);
102 await act(() => {
103 root.render(<Component />);
104 });
105 expect(renders).toBe(2);
106 });
107
108 it('extends React.Component', async () => {
109 let renders = 0;
110 class Component extends React.PureComponent {
111 render() {
112 expect(this instanceof React.Component).toBe(true);
113 expect(this instanceof React.PureComponent).toBe(true);
114 renders++;
115 return <div />;
116 }
117 }
118 const root = ReactDOMClient.createRoot(document.createElement('div'));
119 await act(() => {
120 root.render(<Component />);
121 });
122 expect(renders).toBe(1);
123 });
124
125 it('should warn when shouldComponentUpdate is defined on React.PureComponent', async () => {
126 class PureComponent extends React.PureComponent {
127 shouldComponentUpdate() {
128 return true;
129 }
130 render() {
131 return <div />;
132 }
133 }
134 const root = ReactDOMClient.createRoot(document.createElement('div'));
135 await act(() => {
136 root.render(<PureComponent />);
137 });
138 assertConsoleErrorDev([
139 'PureComponent has a method called shouldComponentUpdate(). ' +
140 'shouldComponentUpdate should not be used when extending React.PureComponent. ' +
141 'Please extend React.Component if shouldComponentUpdate is used.\n' +
142 ' in PureComponent (at **)',
143 ]);
144 });
145 });