带有 React Hooks 的 HoC

HoC with React Hooks

我正在尝试使用 Context APIclass component 移植到 react hooks,但我无法弄清楚出现错误的具体原因是什么。

首先,我的代码:

// contexts/sample.jsx
import React, { createContext, useState, useContext } from 'react'
const SampleCtx = createContext()

const SampleProvider = (props) => {
  const [ value, setValue ] = useState('Default Value')
  const sampleContext = { value, setValue }
  return (
    <SampleCtx.Provider value={sampleContext}>
      {props.children}
    </SampleCtx.Provider>
  )
}

const useSample = (WrappedComponent) => {
  const sampleCtx = useContext(SampleCtx)
  return (
    <SampleProvider>
      <WrappedComponent
        value={sampleCtx.value}
        setValue={sampleCtx.setValue} />
    </SampleProvider>
  )
}

export {
  useSample
}

// Sends.jsx
import React, { Component, useState, useEffect } from 'react'
import { useSample } from '../contexts/sample.jsx'

const Sends = (props) => {
  const [input, setInput ] = useState('')

  const handleChange = (e) => {
    setInput(e.target.value)
  }
  const handleSubmit = (e) => {
    e.preventDefault()

    props.setValue(input)
  }

  useEffect(() => {
    setInput(props.value)
  }, props.value)

  return (
    <form onSubmit={handleSubmit}>
      <input value={input} onChange={handleChange} />
      <button type="submit">Submit</button>
    </form>
  )
}

我得到的错误:

Invariant Violation: 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 https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.

我的代码说明:

我使用 Context API 来管理状态,之前我使用 class component 来制作视图。我希望结构简单明了,不需要更多细节。

我认为它也应该工作,<Sends /> 组件被传递到 useSample HoC 函数,并且它被 sample.jsx<SampleProvider> 组件包裹,所以<Sends /> 可以使用 SampleCtx 上下文提供的 props。但结果是失败。

HoC 模式与 React hooks 一起使用是否无效?还是通过props将变异函数(即useState()制作的setValue)交给其他组件无效?或者,在单个文件中使用 hooks 放置 2 个或更多 function components 是否无效?具体原因请指正

高阶组件是接受一个组件和 returns 另一个组件的函数,返回的组件可以是 class 组件,一个带钩子的功能组件,或者它可以没有全状态逻辑。 在您的示例中,您从 useSample.

返回 jsx
const useSample = (WrappedComponent) => {
  const sampleCtx = useContext(SampleCtx)
  return ( // <-- here
    <SampleProvider>
      <WrappedComponent
        value={sampleCtx.value}
        setValue={sampleCtx.setValue} />
    </SampleProvider>
  )
}

如果你想做一个 HOC,你可以这样做

const withSample = (WrappedComponent) => {
  return props => {
        const sampleCtx = useContext(SampleCtx)
        <WrappedComponent
            value={sampleCtx.value}
            setValue={sampleCtx.setValue} {...props} />
    }
}

所以 HOC 和 Context 是不同的 React 概念。因此,让我们把它分成两部分。

提供商

提供者的主要职责是提供上下文值。上下文值通过 useContext()

使用
const SampleCtx = createContext({});

export const SampleProvider = props => {
  const [value, setValue] = useState("Default Value");
  const sampleContext = { value, setValue };

  useEffect(() => console.log("Context Value: ", value)); // only log when value changes

  return (
    <SampleCtx.Provider value={sampleContext}>
      {props.children}
    </SampleCtx.Provider>
  );
};

HOC

消费者。使用 useContext() 钩子并添加额外的道具。 Returns 一个新组件。

const withSample = WrappedComponent => props => { // curry
  const sampleCtx = useContext(SampleCtx);
  return (
    <WrappedComponent
      {...props}
      value={sampleCtx.value}
      setValue={sampleCtx.setValue}
    />
  );
};

然后使用 HOC:

export default withSample(Send)

组成提供者和消费者 (HOC),我们有:

import { SampleProvider } from "./provider";
import SampleHOCWithHooks from "./send";

import "./styles.css";

function App() {
  return (
    <div className="App">
      <SampleProvider>
        <SampleHOCWithHooks />
      </SampleProvider>
    </div>
  );
}

有关完整代码,请参阅 Code Sandbox