提问者:小点点

带反应钩的HoC


我正在尝试使用上下文API类组件移植到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>
  )
}

不变冲突:无效的挂钩调用。钩子只能在函数组件的主体内部调用。发生这种情况的原因如下:1。React和渲染器(如React DOM)2的版本可能不匹配。你可能违反了Hooks 3的规则。同一应用程序中可能有多个React副本请参见https://reactjs.org/warnings/invalid-hook-call-warning.html有关如何调试和修复此问题的提示。

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

我认为它也应该起作用,

HoC模式与React hook一起使用是否无效?或者通过props将变异函数(即useState()生成的setValue)传递给其他组件是否无效?或者,在单个文件中使用hooks放置两个或多个功能组件是否无效?请告诉我具体原因是什么。


共2个答案

匿名用户

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

供应商

提供者的主要职责是提供上下文值。上下文值通过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>
  );
};

临时的

消费者。使用useContext()hook并添加其他道具。返回一个新组件。

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>
  );
}

有关完整代码,请参见代码沙盒。

匿名用户

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

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

如果你想做一件事,你能做的就是这样

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