@samitouri / QOS-React / commits / f24a0da6e0

Fix useImperativeHandle to have no deps by default (#14801)

* Fix useImperativeHandle to have no deps by default * Save a byte? * Nit: null

Dan Abramov committed Feb 11, 2019 at 18:42 UTC f24a0da6e0f59484e5aafd0825bb1a6ed27d7182
2 files changed +107 -2
packages/react-reconciler/src/ReactFiberHooks.js
+2 -2
@@ -905,7 +905,7 @@ function mountImperativeHandle<T>(
905
906 // TODO: If deps are provided, should we skip comparing the ref itself?
907 const effectDeps =
908 - deps !== null && deps !== undefined ? deps.concat([ref]) : [ref];
908 + deps !== null && deps !== undefined ? deps.concat([ref]) : null;
909
910 return mountEffectImpl(
911 UpdateEffect,
@@ -931,7 +931,7 @@ function updateImperativeHandle<T>(
931
932 // TODO: If deps are provided, should we skip comparing the ref itself?
933 const effectDeps =
934 - deps !== null && deps !== undefined ? deps.concat([ref]) : [ref];
934 + deps !== null && deps !== undefined ? deps.concat([ref]) : null;
935
936 return updateEffectImpl(
937 UpdateEffect,
packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js
+105
@@ -1593,6 +1593,111 @@ describe('ReactHooksWithNoopRenderer', () => {
1593 });
1594 });
1595
1596 + describe('useImperativeHandle', () => {
1597 + it('does not update when deps are the same', () => {
1598 + const INCREMENT = 'INCREMENT';
1599 +
1600 + function reducer(state, action) {
1601 + return action === INCREMENT ? state + 1 : state;
1602 + }
1603 +
1604 + function Counter(props, ref) {
1605 + const [count, dispatch] = useReducer(reducer, 0);
1606 + useImperativeHandle(ref, () => ({count, dispatch}), []);
1607 + return <Text text={'Count: ' + count} />;
1608 + }
1609 +
1610 + Counter = forwardRef(Counter);
1611 + const counter = React.createRef(null);
1612 + ReactNoop.render(<Counter ref={counter} />);
1613 + ReactNoop.flush();
1614 + expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
1615 + expect(counter.current.count).toBe(0);
1616 +
1617 + act(() => {
1618 + counter.current.dispatch(INCREMENT);
1619 + });
1620 + ReactNoop.flush();
1621 + expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
1622 + // Intentionally not updated because of [] deps:
1623 + expect(counter.current.count).toBe(0);
1624 + });
1625 +
1626 + // Regression test for https://github.com/facebook/react/issues/14782
1627 + it('automatically updates when deps are not specified', () => {
1628 + const INCREMENT = 'INCREMENT';
1629 +
1630 + function reducer(state, action) {
1631 + return action === INCREMENT ? state + 1 : state;
1632 + }
1633 +
1634 + function Counter(props, ref) {
1635 + const [count, dispatch] = useReducer(reducer, 0);
1636 + useImperativeHandle(ref, () => ({count, dispatch}));
1637 + return <Text text={'Count: ' + count} />;
1638 + }
1639 +
1640 + Counter = forwardRef(Counter);
1641 + const counter = React.createRef(null);
1642 + ReactNoop.render(<Counter ref={counter} />);
1643 + ReactNoop.flush();
1644 + expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
1645 + expect(counter.current.count).toBe(0);
1646 +
1647 + act(() => {
1648 + counter.current.dispatch(INCREMENT);
1649 + });
1650 + ReactNoop.flush();
1651 + expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
1652 + expect(counter.current.count).toBe(1);
1653 + });
1654 +
1655 + it('updates when deps are different', () => {
1656 + const INCREMENT = 'INCREMENT';
1657 +
1658 + function reducer(state, action) {
1659 + return action === INCREMENT ? state + 1 : state;
1660 + }
1661 +
1662 + let totalRefUpdates = 0;
1663 + function Counter(props, ref) {
1664 + const [count, dispatch] = useReducer(reducer, 0);
1665 + useImperativeHandle(
1666 + ref,
1667 + () => {
1668 + totalRefUpdates++;
1669 + return {count, dispatch};
1670 + },
1671 + [count],
1672 + );
1673 + return <Text text={'Count: ' + count} />;
1674 + }
1675 +
1676 + Counter = forwardRef(Counter);
1677 + const counter = React.createRef(null);
1678 + ReactNoop.render(<Counter ref={counter} />);
1679 + ReactNoop.flush();
1680 + expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
1681 + expect(counter.current.count).toBe(0);
1682 + expect(totalRefUpdates).toBe(1);
1683 +
1684 + act(() => {
1685 + counter.current.dispatch(INCREMENT);
1686 + });
1687 + ReactNoop.flush();
1688 + expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
1689 + expect(counter.current.count).toBe(1);
1690 + expect(totalRefUpdates).toBe(2);
1691 +
1692 + // Update that doesn't change the ref dependencies
1693 + ReactNoop.render(<Counter ref={counter} />);
1694 + ReactNoop.flush();
1695 + expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
1696 + expect(counter.current.count).toBe(1);
1697 + expect(totalRefUpdates).toBe(2); // Should not increase since last time
1698 + });
1699 + });
1700 +
1701 describe('progressive enhancement (not supported)', () => {
1702 it('mount additional state', () => {
1703 let updateA;