首页 > 解决方案 > 访问 HOC 内部的 REDUX 状态

问题描述

首先,我通常是反应和编码的新手,并且已经陷入困境。

我正在尝试构建我可以收藏并在单独页面上呈现的组件。

我正在使用 redux 来存储组件的状态,无论它是否被收藏。

我遇到的问题是在我的HOC (isFavorited) 我无法访问 redux useSelector

const isFavorited = (Component) => {
  const url = "URL"; //This will check wheater im on the page that I always want it rendering 
  const count = useSelector((state) => state.favourite.value); //Need to check weather the render state
  console.log(Component);
  if (count === 1 || url === "url") {
    return (props) => <Component {...props} />;
  }
  return () => <span>No render</span>;
};

const CardLong = isFavorited((props) => {
  const count = useSelector((state) => state.favourite.value);

  const dispatch = useDispatch();
  return (
    **MY JSX IS HERE REMOVED FOR EASY READING**
  );
});

export default CardLong;

错误

标签: reactjsreduxreact-reduxreact-hooksnext.js

解决方案


您应该将反应钩子放在反应函数组件中,而不是纯 JavaScript 高阶函数。

像这样重构它:

index.tsx

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';

const IsFavorited = (Component) => {
  return function Wrapper(props) {
    const count = useSelector((state: any) => state.favourite.value);

    if (count === 1) {
      return <Component {...props} />;
    }
    return <span>No render</span>;
  };
};

const CardLong = IsFavorited((props) => {
  const count = useSelector((state: any) => state.favourite.value);
  console.log('cardlong props.name:', props.name);
  const dispatch = useDispatch();
  return <div>card long</div>;
});

export default CardLong;

index.test.tsx

import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';
import { Provider } from 'react-redux';
import createMockStore from 'redux-mock-store';
import CardLong from '.';

const mockStore = createMockStore();

describe('hoc hooks', () => {
  let container;
  beforeEach(() => {
    container = document.createElement('div');
    document.body.appendChild(container);
  });

  afterEach(() => {
    unmountComponentAtNode(container);
    container.remove();
    container = null;
  });
  test('should no render', () => {
    const store = mockStore({ favourite: { value: 123 } });
    act(() => {
      render(
        <Provider store={store}>
          <CardLong />
        </Provider>,
        container
      );
    });
    expect(container!.innerHTML).toMatchInlineSnapshot(`"<span>No render</span>"`);
  });
  test('should render card long', () => {
    const store = mockStore({ favourite: { value: 1 } });
    act(() => {
      render(
        <Provider store={store}>
          <CardLong name="teresa teng" />
        </Provider>,
        container
      );
    });
    expect(container!.innerHTML).toMatchInlineSnapshot(`"<div>card long</div>"`);
  });
});

测试结果:

 PASS  issues/hoc-hooks/index.test.tsx (8.031 s)
  hoc hooks
    ✓ should no render (16 ms)
    ✓ should render card long (18 ms)

  console.log
    cardlong props.name: teresa teng

      at issues/hoc-hooks/index.tsx:17:11

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   2 passed, 2 total
Time:        8.541 s

推荐阅读