具有React Hooks的HoC

时间:2019-09-04 05:40:49

标签: javascript reactjs react-hooks react-context

我正在尝试将class componentreact hooks移植到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
}

// 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.您可能违反了《胡克规则》 3.您可能在其中包含多个React版本相同的应用程序。有关如何调试和解决此问题的提示,请参见https://reactjs.org/warnings/invalid-hook-call-warning.html

我的代码的解释:

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

我认为它也应该工作,<Sends />组件被传递到useSample HoC函数中,并被<SampleProvider>的{​​{1}}组件包装,因此{ {1}}可以使用sample.jsx上下文提供的<Sends />。但是结果就是失败。

props模式与SampleCtx一起使用是否无效?还是通过HoC将变异函数(即React hooks产生的setValue传递给其他组件是否无效?还是在单个文件中使用useState()放置两个或更多props是无效的吗?请纠正我的具体原因。

2 个答案:

答案 0 :(得分:2)

高阶组件是接受一个组件并返回另一个组件的函数,而返回的组件可以是类组件,带有钩子的功能组件,也可以没有全状态逻辑。 在您的示例中,您将从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} />
    }
}

答案 1 :(得分:1)

因此,HOC和上下文是不同的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()钩子并添加其他道具。返回一个新组件。

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

然后使用HOC:

export default useSample(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