React Hooks - вернуть useContext без нарушения правила Hooks - PullRequest
2 голосов
/ 11 апреля 2019

Я настраиваю этот код, но не могу идти вперед, потому что React жалуется на мой хук.

// globalStateManager.js
import React, { createContext, useContext, useReducer } from 'react';
import PropTypes from 'prop-types';

export const StateContext = createContext();

export const StateProvider = ({
  reducer,
  initialState,
  children,
}) => (
  <StateContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </StateContext.Provider>
);

export const getState = () => useContext(StateContext);

Когда я пытаюсь использовать функцию getState, выдается следующая ошибка:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
    1. You might have mismatching versions of React and the renderer (such as React DOM)
    2. You might be breaking the Rules of Hooks
    3. You might have more than one copy of React in the same app
    See <link> for tips about how to debug and fix this problem.

Как я могу получить доступ к вышеупомянутому контексту при соблюдении этих правил?

EDIT

Я использую функцию getState в действии, которое я создал для извлечения пользователя, вошедшего в систему, например:

// shared/User/actions.js
import { getState } from 'shared/utils/globalStateManager';
import { SET_USER, GET_USER } from './types';

export function setUser(payload) {
  const [state, dispatch] = getState();
  dispatch({
    type: SET_USER,
    payload,
  });
}

export function getUser() {
  const [state, dispatch] = getState();
  dispatch({
    type: GET_USER,
  });
}

... и затем я вызываю его на экран входа в систему:

// components/LogIn
import React, { useEffect, useState } from 'react';
import { setUser, getUser } from 'components/User/actions';

function click() {
  setUser({
    name: 'John',
    phone: '32323232',
  });
}

function useCurrentUser() {
  const [currentUser, setCurrentUser] = useState(null);

  useEffect(() => {
    setCurrentUser(getUser());
  }, []);

  return currentUser;
}

function Login() {
  const currentUser = useCurrentUser();

  return (
    <div>
      {currentUser && (
        <div>
          <h2>User info</h2>
          <ul>
            <li>Name: {currentUser.name}</li>
            <li>CPF: {currentUser.cpf}</li>
            <li>Phone: {currentUser.phone}</li>
          </ul>
        </div>
      )}

      <button type="button" onClick={click}>
        Set User state
      </button>
    </div>
  );
}

export default Login;

1 Ответ

2 голосов
/ 11 апреля 2019

Вы должны убедиться, что вы используете свой пользовательский хук в компоненте функции, и хорошее соглашение - назвать пользовательский хук с префиксом use, например, useStateContext.

const { createContext, useContext, useReducer, Fragment } = React;

const StateContext = createContext();

const StateProvider = ({ reducer, initialState, children }) => (
  <StateContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </StateContext.Provider>
);

const useStateContext = () => useContext(StateContext);

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function App() {
  const [state, dispatch] = useStateContext();

  return (
    <Fragment>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </Fragment>
  );
}

ReactDOM.render(
  <StateProvider reducer={reducer} initialState={initialState}>
    <App />
  </StateProvider>,
  document.getElementById("root")
);
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
...