如何在单独的函数中使用useContext - ReactJS

问题描述 投票:0回答:1

我试图将 useContext 的使用和随后的数组操作分离到可调用函数(ChangeContent)中,以便我可以在其他函数/组件中使用它,而不必在各处定义相同的代码。 ChangeContent 在新文件中将具有类似 AddTab 和 DeleteTab 等姊妹函数。

我尝试了两种不同的方法来调用 ChangeContent,如注释掉的代码所示。 使用 () 调用 ChangeContent 会更进一步,出现 Invalid hook call 错误。 调用 ChangeContent 似乎根本没有做任何事情。

我已经删除了代码中不相关的部分,留下了问题的核心部分。 应用程序有一个名为 SideBar 的组件,其中包含可以更改 tabArray 中内容的按钮。 当更改内容的代码直接位于 SideBar 内时,它可以正常工作。 (状态数组中会有更多的元素) 将来,我想要操作其他组件中的内容,因此我希望将代码提取到可以在我的应用程序中调用的单个位置。

实际上,这 3 个函数不是在同一个文件中定义的,我只是使用codesandbox 来复制我的错误,所以它都在一个地方,这样我就可以显示我的问题。

任何帮助将不胜感激。

import React, {createContext, useState, useContext} from "react";

export const TabContext = createContext()

export default function App() {

  const [tabArray, setTabArray] = useState([{TabText:'Home' ,Selected:true}])

  return (
    <div className="App">
      <TabContext.Provider value= {{tabArray, setTabArray}}>
      <SideBar/>
      {tabArray.map((v,i) => <div key={i}>{v.TabText} </div>)}
      </TabContext.Provider>
    </div>
  );
}

export function SideBar() {

  return (            
         <div>
                <button onClick={() => ChangeContent("All Commodity")}> All Commodity </button> 
                {/* <button onClick={() => <ChangeContent text={"All Commodity"}/>}> All Commodity </button>  */}
        </div>
  )
}

export function ChangeContent (text) {
{/* export function ChangeContent ({text}) { */}
  
    const { tabArray , setTabArray} = useContext(TabContext)
    setTabArray(oldValues => {
      return oldValues.map((v) => {
        if (v.Selected) {
        return {...v,TabText:text}
        }
        else {return {...v}}
      })
    })
  }
reactjs react-hooks react-context
1个回答
0
投票

我不是 100% 确定你想要实现什么。我尝试按照这些思路实现一些东西 - 我上下文包装选项卡的值,这些值在单击时会更改:

https://codesandbox.io/p/sandbox/priceless-banach-mjwxx4

//app.js
import Sidebar from "./Sidebar";
import "./styles.css";
import { TabContextProvider } from "./TabContext";

export default function App() {
  return (
    <TabContextProvider>
      <Sidebar />
    </TabContextProvider>
  );
}
//tabcontext.js
import { createContext, useContext, useState } from "react";

const TabContext = createContext();

export const TabContextProvider = ({ children }) => {
  const [tabArray, setTabArray] = useState([
    { TabText: "Home", Selected: true },
  ]);

  const changeContent = (text) => {
    setTabArray((prev) =>
      prev.map((v) => (v.Selected ? { ...v, TabText: text } : { ...v }))
    );
  };

  return (
    <TabContext.Provider value={{ tabArray, setTabArray, changeContent }}>
      {children}
    </TabContext.Provider>
  );
};

export const useTabContext = () => {
  return useContext(TabContext);
};
import { useTabContext } from "./TabContext";

export default function Sidebar() {
  const { changeContent, tabArray } = useTabContext();

  return (
    <div>
      {tabArray.map((tab) => (
        <button onClick={() => changeContent("All Commodit")}>
          {tab.TabText}
        </button>
      ))}
    </div>
  );
}

这种方法略有不同。

首先,我会取出状态并将其直接放入上下文中

TabContext.js
- 在
App.js
中声明它没有意义 - 每次与上下文交互时值都会改变 - 整个应用程序将重新渲染(因为当您更新组件的状态时,所有子组件都会重新渲染)。我总是导出像
TabContextProvider
useTabContext
这样的函数 - 这使得它更好用。

其次,您可以将

changeContent
函数直接放在上下文中。在我看来,这似乎是一个适合它居住的好地方。您可以使用三元运算符代替
setState
来简化
if else
内部的逻辑。

最后,在

Sidebar.js
中,您可以直接从上下文中获取
changeContent
函数并在那里使用它。单击该按钮会将状态更改为所提供文本的值。我还注意到您没有使用上下文中的值 - 您将值硬编码为:

<button onClick={() => ChangeContent("All Commodity")}> All Commodity </button> 

我将其更改为直接使用上下文中的值,尽管我不完全确定您的目标是什么:

{tabArray.map((tab) => (
    <button onClick={() => changeContent("All Commodit")}>
        {tab.TabText}
    </button>
))}

希望这有帮助:)

© www.soinside.com 2019 - 2024. All rights reserved.