簡體   English   中英

動態導航 React 路由 dom

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM