我有一个自定义钩子写显示或隐藏一个列表时,一个按钮单击。下面是我编写的自定义钩子代码片段:
import { useEffect } from "react";
import { useState } from "react";
function useVisibilityStatus() {
const [isVisible, setIsVisible] = useState(true);
useEffect( () => {
setIsVisible(!isVisible);
}, [isVisible]);
return isVisible;
}
export default useVisibilityStatus;
在另一个组件中,我编写了查看或隐藏列表的逻辑。
import ProductListView from "../common/ProductListView";
import SideNavView from "../common/SideNavView";
import SimpleMap from '../googlemap/SimpleMap';
import useVisibilityStatus from '../customhooks/useVisibilityStatus';
function ServiceContentView() {
const listVisible = useVisibilityStatus();
return (
<div className="row p-0 vw-100 service-view-body bg-primary position-relative">
<div className="zindex-value position-absolute">
<div className="service-view-sidenav float-end">
<SideNavView />
</div>
</div>
{listVisible && <ProductListView />}
<SimpleMap />
</div>
);
}
export default ServiceContentView;
在SideNavView
中,我有一个按钮,单击它会显示产品列表或隐藏它,如果它是可见的。SideNavView
是不完整的,因为我有点纠结于如何在ReactJS中满足我的需求。
import useVisibilityStatus from '../customhooks/useVisibilityStatus';
function SideNavView() {
const listVisible = useVisibilityStatus();
const handleClick = () => {
}
return (
<div className="">
<div className="row">
<div className="card p-0 w-100 border-radius-none sidenav-view" onClick={handleClick}>
<span className="text-center mt-2 text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" className="bi bi-card-list" viewBox="0 0 16 16">
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
<path d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8zm0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-1-5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zM4 8a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm0 2.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/>
</svg>
</span>
<div className="card-body p-0">
<h5 className="card-title text-center text-white">View Products</h5>
</div>
</div>
</div>
</div>
)
}
export default SideNavView;
React钩子不会神奇地共享状态,所以在当前的useVisibilityStatus
实现中,它们将各自拥有并独立更新自己的状态。
你能做的是创建一个React Context来保存单个isVisible
状态值,并将它和一个更新函数公开给消费者。
import { createContext, useContext, useState } from 'react';
const VisibleContext = createContext({
isVisible: false,
toggleIsVisible: () => {},
});
export const useVisibilityStatus = () => useContext(VisibleContext);
const VisibleContextProvider = ({ children }) => {
const [isVisible, setIsVisible] = useState(true);
const toggleIsVisible = () => setIsVisible(isVisible => !isVisible);
return (
<VisibleContext.Provider value={{ isVisible, toggleIsVisible }}>
{children}
</VisibleContext.Provider>
);
};
export default VisibleContextProvider;
VisibleContextProvider
只需要包装ReactTree的一部分,该部分包含需要访问其上下文值的组件,例如ServiceContentView
和SideNavView
,并且这些组件使用useVisibilityStatus
读取当前isVisible
状态值或访问toggleIsVisible
更新函数。
import VisibleContextProvider from '../path/to/VisibleContextProvider';
...
return (
...
<VisibleContextProvider>
...
<ServiceContentView />
...
</VisibleContextProvider>
...
);
import ProductListView from "../common/ProductListView";
import SideNavView from "../common/SideNavView";
import SimpleMap from '../googlemap/SimpleMap';
import { useVisibilityStatus } from '../path/to/VisibleContextProvider';
function ServiceContentView() {
const { isVisible } = useVisibilityStatus();
return (
<div className="row p-0 vw-100 service-view-body bg-primary position-relative">
<div className="zindex-value position-absolute">
<div className="service-view-sidenav float-end">
<SideNavView />
</div>
</div>
{isVisible && <ProductListView />}
<SimpleMap />
</div>
);
}
export default ServiceContentView;
import { useVisibilityStatus } from '../path/to/VisibleContextProvider';
function SideNavView() {
const { toggleIsVisible } = useVisibilityStatus();
const handleClick = () => {
toggleIsVisible();
};
return (
<div className="">
<div className="row">
<div
className="...."
onClick={handleClick}
>
<span className="text-center mt-2 text-white">
...
</svg>
</span>
<div className="card-body p-0">
<h5 className="....">View Products</h5>
</div>
</div>
</div>
</div>
)
}
export default SideNavView;
您不需要为该任务使用自定义钩子。更好的解决方案是将可见性状态保存到主组件的容器中,并将其作为props传递给子组件。
要在深度嵌套的组件之间共享状态,可以使用context
VisibilityContext.jsx
import { createContext, useState } from 'react'
const VisibilityContext = createContext({
Visibility: {}
})
export const VisibilityContextProvider = ({ children })=>{
const [Visibility, SetVisibility] = useState({})
return (
<VisibilityContext.Provider value={{ Visibility, SetVisibility }}>
{children}
</VisibilityContext.Provider>
)
}
export default VisibilityContext
useVisibilityStatus.js
import { useState, useContext, useCallback } from "react";
import VisibilityContext from 'path/to/VisibilityContext.jsx'
const useVisibilityStatus = (scope) => {
const { Visibility, SetVisibility } = useContext(VisibilityContext)
const ToggleVisibility = useCallback(() => {
SetVisibility(prev => !prev)
}, [SetVisibility])
return {
IsVisible: Visibility[scope] ?? false,
ToggleVisibility
}
}
export default useVisibilityStatus;
你需要用VisibilityContextProvider
包裹SideNavView
和ServiceContentView
SideNavView
和ServiceContentView
父节点
import { VisibilityContextProvider } from 'path/to/VisibilityContext.jsx'
const ... = () => {
return (
<VisibilityContextProvider>
{/* SideNavView and ServiceContentView */}
</VisibilityContextProvider>
)
}
ServiceContentView.jsx
import useVisibilityStatus from 'path/to/useVisibilityStatus.js'
const ServiceContentView = () => {
const { IsVisible } = useVisibilityStatus('ServiceContentView')
return (
...
{IsVisible && <ProductListView />}
...
)
}
SideNavView.jsx
import useVisibilityStatus from 'path/to/useVisibilityStatus.js'
const SideNavView = () => {
const { ToggleVisibility } = useVisibilityStatus('ServiceContentView')
const handleClick = () => {
ToggleVisibility()
}
}