从jQuery迁移至ReactJS遇阻:DOM访问与请求事件处理咨询
Let's break down your two main questions with practical, React-specific solutions that align with your existing code structure:
1. Accessing Master Page DOM Elements in JSX
Since the HyperlinkNavigation element lives outside your React component (in the Master Page), you can't use React refs directly for it. Instead, you'll use React's useEffect hook to safely access the DOM after your component mounts (ensuring the element exists in the DOM tree).
Example Implementation:
import React, { useEffect } from 'react'; function SessionManager() { useEffect(() => { // Get reference to the master page navigation button const navButton = document.getElementById("HyperlinkNavigation"); if (navButton) { // Apply the same class styling as your original jQuery code navButton.className = "navigation__button navigation__button--back"; // Attach the click handler const handleNavClick = () => { navButton.href = "applications.aspx"; }; navButton.addEventListener('click', handleNavClick); // Cleanup: Remove event listener when component unmounts return () => { navButton.removeEventListener('click', handleNavClick); }; } }, []); // Empty dependency array ensures this runs once on mount return ( <div className="sessionmanager"> {/* Your React UI content here */} </div> ); } export default SessionManager;
Key Notes:
- Always add a check for
navButtonto avoid errors if the element isn't loaded yet. - Use the cleanup function in
useEffectto remove event listeners—this prevents memory leaks when your component unmounts.
2. Replacing beginRequest/endRequest Logic in React
Your original code uses WebForms' PageRequestManager to preserve scroll position during partial postbacks. There are two approaches depending on whether you're still using WebForms partial postbacks or migrating to React-native async requests:
Option 1: Keep Using WebForms Partial Postbacks
You can still listen to the PageRequestManager events from within your React component. Just make sure to clean up the event listeners when the component unmounts:
import React, { useEffect } from 'react'; function SessionManager() { useEffect(() => { const prm = window.Sys.WebForms.PageRequestManager.getInstance(); let xPos, yPos; const scroolBarPlaceHolder = '<%= ClientID %>'; // Keep your existing ASP.NET variable const beginRequestHandler = (sender, args) => { // Capture scroll position before postback const element = document.getElementById(scroolBarPlaceHolder); if (element) { xPos = element.scrollLeft; yPos = element.scrollTop; } }; const endRequestHandler = (sender, args) => { // Restore scroll position after postback const element = document.getElementById(scroolBarPlaceHolder); if (element) { element.scrollLeft = xPos; element.scrollTop = yPos; } }; // Register event listeners prm.add_beginRequest(beginRequestHandler); prm.add_endRequest(endRequestHandler); // Cleanup: Remove listeners on unmount return () => { prm.remove_beginRequest(beginRequestHandler); prm.remove_endRequest(endRequestHandler); }; }, []); // ... rest of your component code }
Option 2: Migrate to React Async Requests (Recommended)
If you're moving away from WebForms postbacks to React-friendly async calls (like Axios), use Axios interceptors to replicate the scroll position logic:
import React, { useEffect, useState } from 'react'; import axios from 'axios'; function SessionManager() { const [scrollPos, setScrollPos] = useState({ x: 0, y: 0 }); const scroolBarPlaceHolder = '<%= ClientID %>'; useEffect(() => { // Add Axios request interceptor (runs before request starts) const requestInterceptor = axios.interceptors.request.use(config => { const element = document.getElementById(scroolBarPlaceHolder); if (element) { setScrollPos({ x: element.scrollLeft, y: element.scrollTop }); } return config; }); // Add Axios response interceptor (runs after request completes) const responseInterceptor = axios.interceptors.response.use(response => { const element = document.getElementById(scroolBarPlaceHolder); if (element) { element.scrollLeft = scrollPos.x; element.scrollTop = scrollPos.y; } return response; }); // Cleanup: Remove interceptors when component unmounts return () => { axios.interceptors.request.eject(requestInterceptor); axios.interceptors.response.eject(responseInterceptor); }; }, [scrollPos]); // ... rest of your component code }
Bonus: Migrating User Activity Tracker & Ping Logic
Here's how to port your activity tracking and ping timer to React:
import React, { useEffect, useState, useRef } from 'react'; function SessionManager() { const [userActivity, setUserActivity] = useState(true); const socketID = 'your-socket-id'; // Replace with your actual socket ID logic const pingTimerRef = useRef(null); useEffect(() => { // Track user activity const handleActivity = () => setUserActivity(true); ['mousedown', 'touchstart', 'mousewheel', 'keydown'].forEach(event => { document.addEventListener(event, handleActivity); }); // Set up ping interval pingTimerRef.current = setInterval(() => { makePing(socketID, userActivity); setUserActivity(false); // Reset activity flag after ping }, 5000); // Cleanup: Remove event listeners and clear timer return () => { ['mousedown', 'touchstart', 'mousewheel', 'keydown'].forEach(event => { document.removeEventListener(event, handleActivity); }); clearInterval(pingTimerRef.current); }; }, [socketID, userActivity]); // Define your makePing function const makePing = (socketId, activity) => { // Your existing ping logic here (e.g., Axios call to server) }; return ( <div className="sessionmanager"> {/* Your React UI content */} </div> ); }
内容的提问来源于stack exchange,提问作者hightides1973

