我试图将 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}}
})
})
}
我不是 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>
))}
希望这有帮助:)