[英]Dynamic navigation React router dom
我有一份餐館清單。 我想點擊一家餐館的名字到go到它的頁面。 我使用 "react-router-dom": "^6.4.4"
在 RestaurantItem.jsx 文件中,我執行了以下操作:
const navigate = useNavigate()
...
<div onClick={() => navigate('/restaurant/' + restaurant.id)} className={cl.name}>
{restaurant.name}
</div>
我寫了這個路由:
<BrowserRouter>
<Routes>
<Route path="/" element={<Header/>}>
<Route index element={<Main/>}/>
<Route path="/restaurant/:id" element={<Restaurant/>}/>
<Route
path="*"
element={<Navigate to="/" replace />}
/>
</Route>
</Routes>
</BrowserRouter>);
現在,當您單擊餐廳名稱時,瀏覽器地址欄中的地址會發生應有的變化。 但是我看到我面前有一個白色的屏幕。 如果我刷新頁面,我會看到餐廳頁面。 切換回主用就沒有這個問題了。
雖然 React 日志對我來說非常無用,但我所了解的是某些主頁組件在其道具中獲得 null,因此 React 無法呈現主頁。 但與此同時,我已經想要 go 到另一個頁面,我現在不需要主頁面。
以下是日志中提到的組件。
使用按下按鈕:
export const usePressingButton = (buttonRef) => {
const [isPressing, setIsPressing] = useState(false)
useEffect(() => {
buttonRef.current.addEventListener('mousedown', (event) => setIsPressing(true))
buttonRef.current.addEventListener('mouseup', (event) => setIsPressing(false))
return () => {
buttonRef.current.removeEventListener('mousedown', (event) => setIsPressing(true))
buttonRef.current.removeEventListener('mouseup', (event) => setIsPressing(false))
}
}, [])
return isPressing
};
選擇菜系:
const SelectCuisineLine = ({cuisines, setCuisines, selectСuisine}) => {
const lineRef = useRef()
const innerLineVisorRef = useRef()
const rightArrow = useRef()
const leftArrow = useRef()
const leftRedSignal = useRef()
const rightRedSignal = useRef()
const [arrowsPressed, setArrowsPressed] = useState({left: false, right: false})
const [linePosition, setLinePosition] = useState(0)
const [limitPositions, setLimitPositions] = useState({left: true, right: false})
const [lineLength, setLineLength] = useState(0)
const [step, setStep] = useState(0)
const [currentCuisine, setCurrentCuisine] = useState('ALL')
useEffect(() => {
setLineLength(cuisines.length * 130)
setStep(Math.floor(getLineVisorWidth() / 130) * 130)
}, [])
useEffect(() => {
rightArrow.current.addEventListener('mousedown', (event) => setArrowsPressed({
...arrowsPressed,
right: true
}));
rightArrow.current.addEventListener('mouseup', (event) => setArrowsPressed({
...arrowsPressed,
right: false
}));
leftArrow.current.addEventListener('mousedown', (event) => setArrowsPressed({
...arrowsPressed,
left: true
}));
leftArrow.current.addEventListener('mouseup', (event) => setArrowsPressed({
...arrowsPressed,
left: false
}));
return () => {
rightArrow.current.removeEventListener('mousedown', (event) => setArrowsPressed({
...arrowsPressed,
right: true
}));
rightArrow.current.removeEventListener('mouseup', (event) => setArrowsPressed({
...arrowsPressed,
right: false
}));
leftArrow.current.removeEventListener('mousedown', (event) => setArrowsPressed({
...arrowsPressed,
left: true
}));
leftArrow.current.removeEventListener('mouseup', (event) => setArrowsPressed({
...arrowsPressed,
left: false
}));
}
}, [])
useEffect(() => {
if (arrowsPressed.right && limitPositions.right) {
lineRef.current.setAttribute('style', 'left:' + (linePosition - 10) + 'px')
rightRedSignal.current.setAttribute('style', 'box-shadow: 0 0 8px 2px red;')
} else if (!arrowsPressed.right) {
rightRedSignal.current.setAttribute('style', 'box-shadow: none;')
}
if (arrowsPressed.left && limitPositions.left) {
lineRef.current.setAttribute('style', 'left:' + (linePosition + 10) + 'px')
leftRedSignal.current.setAttribute('style', 'box-shadow: 0 0 8px 2px red;')
} else if (!arrowsPressed.left) {
leftRedSignal.current.setAttribute('style', 'box-shadow: none;')
}
}, [arrowsPressed])
function getLineVisorWidth() {
return parseInt(window.getComputedStyle(innerLineVisorRef.current).width.replace('px', ''), 10)
}
function leftMotion() {
setLimitPositions({...limitPositions, right: false})
if (linePosition + step > 0) {
lineRef.current.setAttribute('style', 'left: 0')
setLinePosition(0)
setLimitPositions({...limitPositions, left: true})
return
}
lineRef.current.setAttribute('style', 'left:' + (linePosition + step) + 'px')
setLinePosition(linePosition + step)
if (limitPositions.left && arrowsPressed.left) {
lineRef.current.setAttribute('style', 'left:' + (linePosition + 10) + 'px')
}
}
function rightMotion() {
setLimitPositions({...limitPositions, left: false})
lineRef.current.setAttribute('style', 'left:' + (linePosition - step) + 'px')
setLinePosition(linePosition - step)
const lineVisorWidth = getLineVisorWidth()
if (lineVisorWidth > (lineLength - (Math.abs(linePosition))) - lineVisorWidth) {
const limitRightPosition = lineLength - lineVisorWidth
lineRef.current.setAttribute('style', 'left:' + (-limitRightPosition) + 'px')
setLinePosition(-limitRightPosition)
setLimitPositions({...limitPositions, right: true})
}
}
return (
<div className="externalLineVisor">
<div style={{margin: "3px", float: "left"}}>
<Arrow
direction='left'
onClick={leftMotion}
ref={leftArrow}
/>
</div>
<div className="innerLineVisor" ref={innerLineVisorRef}>
<div className="cuisineLine" ref={lineRef}>
{cuisines.map(cuisine =>
<SelectCuisineButton
key={cuisine.id}
selectСuisine={selectСuisine}
currentCuisine={currentCuisine}
setCurrentCuisine={setCurrentCuisine}
>
{cuisine}
</SelectCuisineButton>
)}
</div>
<div className={limitPositions.left ? "leftBlur off" : "leftBlur"}/>
<div className={limitPositions.right ? "rightBlur off" : "rightBlur"}/>
<div className="leftRedSignal" ref={leftRedSignal}/>
<div className="rightRedSignal" ref={rightRedSignal}/>
</div>
<div style={{margin: "3px", float: "right"}}>
<Arrow
direction='right'
onClick={rightMotion}
ref={rightArrow}
/>
</div>
</div>
);
};
export default SelectCuisineLine;
特別優惠:
const SpecialOffer = ({trySpecialOffer}) => {
const leftArrowRef = useRef()
const rightArrowRef = useRef()
const isLeftArrowPressing = usePressingButton(leftArrowRef)
const isRightArrowPressing = usePressingButton(rightArrowRef)
const areaOfVisibilityRef = useRef()
const [specialOffers, setSpecialOffers] = useState([])
const [currentOfferIndex, setCurrentOfferIndex] = useState(0)
const [areaOfVisibilityWidth, setAreaOfVisiblyWidth] = useState(0)
const [lineLength, setLineLength] = useState(0)
const [linePosition, setLinePosition] = useState(0)
const [fetchSpecialOffers, isLoading, error] = useFetching(async () => {
const response = await SpecialOfferAPI.getAll()
setSpecialOffers(response.data)
})
useEffect(() => {
fetchSpecialOffers()
setAreaOfVisiblyWidth(areaOfVisibilityRef.current.offsetWidth)
}, [])
useEffect(() => {
setLineLength(areaOfVisibilityWidth * specialOffers.length)
}, [specialOffers])
useEffect(() => {
if (isLeftArrowPressing && linePosition === 0) {
setLinePosition(20)
}
if (!isLeftArrowPressing && linePosition === 20) {
setLinePosition(0)
}
if (isRightArrowPressing && linePosition === areaOfVisibilityWidth - lineLength) {
setLinePosition(areaOfVisibilityWidth - lineLength - 20)
}
if (!isRightArrowPressing && linePosition === (areaOfVisibilityWidth - lineLength - 20)) {
setLinePosition(areaOfVisibilityWidth - lineLength)
}
}, [isLeftArrowPressing, isRightArrowPressing])
function rightMotion() {
if (linePosition > areaOfVisibilityWidth - lineLength) {
setLinePosition(linePosition - areaOfVisibilityWidth)
setCurrentOfferIndex(currentOfferIndex + 1)
}
}
function leftMotion() {
if (linePosition < 0) {
setLinePosition(linePosition + areaOfVisibilityWidth)
setCurrentOfferIndex(currentOfferIndex - 1)
}
}
function tryCurrentOffer() {
trySpecialOffer(specialOffers[currentOfferIndex].restaurant)
}
return (
<div className="specialOffer">
<div className="somethingNewText">ЧТО-ТО НОВОЕ</div>
<div className="specialOfferCenter">
<div className="arrowArea">
<Arrow
direction='left'
onClick={leftMotion}
ref={leftArrowRef}
/>
</div>
<div className="areaOfVisibility" ref={areaOfVisibilityRef}>
{areaOfVisibilityWidth > 0 &&
<SpecialOfferLine
specialOffers={specialOffers}
itemWidth={areaOfVisibilityWidth - 1}
lineLength={lineLength}
linePosition={linePosition}
/>}
</div>
<div className="arrowArea right">
<Arrow
direction='right'
onClick={rightMotion}
ref={rightArrowRef}
/>
</div>
</div>
<div className="wantToTry" onClick={tryCurrentOffer}>ГДЕ ПОПРОБОВАТЬ?</div>
</div>
);
};
export default SpecialOffer;
箭:
const Arrow = forwardRef((props, ref) => (
<div className="arrowContainer" onClick={props.onClick} ref={ref}>
<div className={props.direction === 'left' ? "left1" : "left1 right1"}/>
<div className={props.direction === 'left' ? "left2" : "left2 right2"}/>
</div>
));
export default Arrow;
我究竟做錯了什么?
在沒有運行代碼演示的情況下,我看到的最接近問題的事情是在useEffect
掛鈎的清理函數中卸載組件時引用 ref 值。 事件偵聽器還應該傳遞一個穩定的處理程序引用。 換句話說,刪除的 function 需要與添加的 function 相同。
嘗試為事件創建偵聽器回調並在掛鈎的回調 scope 中保存 ref 的副本,並在清理函數中引用它。
例子:
export const usePressingButton = (buttonRef) => {
const [isPressing, setIsPressing] = useState(false);
useEffect(() => {
const ref = buttonRef.current;
const setTrue = (event) => setIsPressing(true);
const setFalse = (event) => setIsPressing(false);
ref.addEventListener('mousedown', setTrue);
ref.addEventListener('mouseup', setFalse);
return () => {
ref.removeEventListener('mousedown', setTrue);
ref.removeEventListener('mouseup', setFalse);
}
}, []);
return isPressing;
};
對SelectCuisineLine
組件中的其他useEffect
掛鈎和處理程序執行相同的操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.