带有 React Hooks 的 HoC

cad*_*zah 9 javascript reactjs react-context react-hooks

我正在尝试从 with 移植class componentreact hookswith Context API,但我无法弄清楚出现错误的具体原因是什么。

首先,我的代码:

// 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
}
Run Code Online (Sandbox Code Playgroud)
// 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>
  )
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误:

不变违规:无效的挂钩调用。钩子只能在函数组件的主体内部调用。发生这种情况的原因之一可能是: 1. 您的 React 和渲染器版本可能不匹配(例如 React DOM) 2. 您可能违反了 Hooks 规则 3. 您可能在其中拥有多个 React 副本有关如何调试和解决此问题的提示,请参阅https://reactjs.org/warnings/invalid-hook-call-warning.html 。

我的代码的解释:

我以前是Context API管理状态的,之前我用class components 来制作视图。我希望结构很简单,不需要更多细节。

我认为它也应该可以工作,<Sends />组件被传递到HoC 函数中,并且它被的组件useSample包装起来,这样就可以使用上下文提供的内容。但结果是失败。<SampleProvider>sample.jsx<Sends />propsSampleCtx

HoC使用该模式无效吗React hooks?或者通过 来将变异函数(即setValue所做的useState())交给其他组件是无效的吗propsfunction components或者,将 2 个或多个使用hooks放在一个文件中是否无效?具体原因是什么,请指正。

Jos*_* D. 16

所以 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>
  );
};
Run Code Online (Sandbox Code Playgroud)

HOC

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

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

然后使用 HOC:

export default withSample(Send)
Run Code Online (Sandbox Code Playgroud)

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

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

import "./styles.css";

function App() {
  return (
    <div className="App">
      <SampleProvider>
        <SampleHOCWithHooks />
      </SampleProvider>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

有关完整代码,请参阅代码沙箱。

  • eslint 将为 HOC 生成警告,因为无法在回调方法内调用钩子。`React Hook“useContext”无法在回调内调用。React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用。eslint(react-hooks/rules-of-hooks)` (8认同)

Pri*_*Das 6

高阶组件是接受一个组件并返回另一个组件的函数,返回的组件可以是类组件、带有钩子的功能组件,也可以没有状态逻辑。在您的示例中,您从 useSample 返回 jsx。

const useSample = (WrappedComponent) => {
  const sampleCtx = useContext(SampleCtx)
  return ( // <-- here
    <SampleProvider>
      <WrappedComponent
        value={sampleCtx.value}
        setValue={sampleCtx.setValue} />
    </SampleProvider>
  )
}
Run Code Online (Sandbox Code Playgroud)

如果你想做一个 HOC 你可以做这样的事情

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

Run Code Online (Sandbox Code Playgroud)

  • 提供程序应该包装您想要访问上下文状态的应用程序的整个部分,您不需要将每个组件包装在提供程序中。例如,如果您希望此数据在整个应用程序中可用,则使用提供程序包装您的根组件。 (2认同)