显示/隐藏ReactJS中其他组件的组件



我有一个自定义钩子写显示或隐藏一个列表时,一个按钮单击。下面是我编写的自定义钩子代码片段:

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的一部分,该部分包含需要访问其上下文值的组件,例如ServiceContentViewSideNavView,并且这些组件使用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包裹SideNavViewServiceContentView

SideNavViewServiceContentView父节点

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