JavaScript and React course · Module 5: useEffect and Custom Hooks
References with useRef
In this lesson8
On our cosmic journey through React, sometimes we need to maintain certain data or references to DOM elements that persist between renders but don't cause the component to re-render. The useRef hook is like a storage compartment on a spaceship - it lets you store important things that don't change with every maneuver of the ship.
What is useRef?
The useRef hook is one of the built-in hooks in React that:
- Creates a mutable reference field that survives throughout the entire component lifecycle
- Does not cause component re-rendering when its value changes
- Can be used to store references to DOM elements or any other values
Basic syntax:
1const refContainer = useRef(initialValue);The returned object refContainer has a .current property that is initialized with the initial value (initialValue). This value can be changed without triggering a re-render.
Main use cases for useRef
1. Accessing DOM elements
One of the most popular uses of useRef is gaining direct access to DOM nodes:
1function SpaceshipControls() {
2 // Creating reference
3 const thrusterControlRef = useRef(null);
4
5 // Function using reference to DOM element
6 const focusThrusterControl = () => {
7 // Access DOM element through .current property
8 thrusterControlRef.current.focus();
9 };
10
11 return (
12 <div className="control-panel">
13 <h2>Thruster Control Panel</h2>
14
15 {/* Przypisanie referencji do elementu input */}
16 <input
17 ref={thrusterControlRef}
18 type="range"
19 min="0"
20 max="100"
21 className="thruster-slider"
22 />
23
24 <button onClick={focusThrusterControl}>
25 Activate thrust control
26 </button>
27 </div>
28 );
29}In this example:
- We create a reference
thrusterControlRefusinguseRef(null) - We assign this reference to the
inputelement using therefattribute - We use the reference to call the
focus()method on the DOM element
2. Storing mutable values between renders
useRef can also be used to store values that:
- Should not cause a re-render when changed
- Must remain stable throughout the component's lifecycle
1function MissionTimer() {
2 const [seconds, setSeconds] = useState(0);
3 const timerIdRef = useRef(null);
4
5 // Function to start the timer
6 const startTimer = () => {
7 if (timerIdRef.current !== null) return; // Avoid duplicate timers
8
9 timerIdRef.current = setInterval(() => {
10 setSeconds(s => s + 1);
11 }, 1000);
12 };
13
14 // Function to stop the timer
15 const stopTimer = () => {
16 clearInterval(timerIdRef.current);
17 timerIdRef.current = null;
18 };
19
20 // Clean up interval on unmount
21 useEffect(() => {
22 return () => {
23 if (timerIdRef.current !== null) {
24 clearInterval(timerIdRef.current);
25 }
26 };
27 }, []);
28
29 return (
30 <div className="mission-timer">
31 <p>Mission time: {seconds} seconds</p>
32 <button onClick={startTimer}>Start</button>
33 <button onClick={stopTimer}>Stop</button>
34 </div>
35 );
36}In this example, we use useRef to store the interval ID. This is an ideal use case because:
- We don't need a re-render when the interval ID changes
- We need to preserve the ID between renders to be able to stop the interval
- This value is not used directly in the rendered JSX
3. Tracking previous values
One interesting use of useRef is tracking previous values of props or state:
1function usePrevious(value) {
2 const ref = useRef();
3
4 // Update ref.current after rendering
5 useEffect(() => {
6 ref.current = value;
7 }, [value]);
8
9 // Returns the previous value (undefined during the first render)
10 return ref.current;
11}
12
13function AsteroidTracker({ asteroidId }) {
14 const [asteroidData, setAsteroidData] = useState(null);
15 // Track the previous ID
16 const previousAsteroidId = usePrevious(asteroidId);
17
18 // Effect that logs the change of the observed asteroid
19 useEffect(() => {
20 if (previousAsteroidId !== asteroidId) {
21 console.log(`Tracking changed from asteroid ${previousAsteroidId} to ${asteroidId}`);
22 // Here we could fetch new data about the asteroid
23 }
24 }, [asteroidId, previousAsteroidId]);
25
26 // Rendering...
27}The usePrevious hook uses useRef to store the previous value. The reference is updated in useEffect, which runs after rendering, so the value stored in the ref is always one render cycle "behind" the current value.
4. Avoiding unnecessary effects
useRef can help with optimization by avoiding unnecessary effects:
1function TelemetryMonitor({ shipId }) {
2 const [data, setData] = useState(null);
3 const [isConnected, setIsConnected] = useState(false);
4
5 // Store the ID to avoid unnecessary connection changes
6 const lastShipIdRef = useRef(shipId);
7
8 useEffect(() => {
9 // Check if the ship ID actually changed
10 if (lastShipIdRef.current === shipId && isConnected) {
11 console.log('Ship hasn't changed, skipping reconnection');
12 return;
13 }
14
15 // Update ref with the new ID
16 lastShipIdRef.current = shipId;
17
18 // Establish connection...
19 console.log(`Connecting to ship telemetry ${shipId}...`);
20
21 const connection = telemetryService.connect(shipId);
22 setIsConnected(true);
23
24 connection.onData(newData => {
25 setData(newData);
26 });
27
28 return () => {
29 console.log(`Disconnecting ship telemetry ${shipId}...`);
30 connection.disconnect();
31 setIsConnected(false);
32 };
33 }, [shipId]);
34
35 // Rendering...
36}useRef vs useState - when to use which?
The difference between useRef and useState is crucial to understand:
| Aspect | useRef | useState |
|---|---|---|
| Powoduje re-rendering | No | Yes |
| Preserves value between renders | Yes | Yes |
| Accessing value | Through the .current property | Directly by reading the state variable |
| Updating value | Direct mutation ref.current = newValue | Through updater function setState(newValue) |
| When to use? | For values that don't affect render output | For values that should trigger re-rendering |
When to use useRef:
- Accessing DOM elements
- Storing timer and interval IDs
- Storing previous values
- Values that change frequently but don't affect UI
- Storing class instances and objects that shouldn't be recreated on every render
When to use useState:
- Data that affects what the user sees
- Values whose changes should cause UI updates
- State that controls the behavior or appearance of the user interface
Advanced useRef patterns
1. Callback Refs
Sometimes we need greater control over when a ref is assigned. In such cases, we can use a callback ref:
1function SpectrumAnalyzer() {
2 const [frequency, setFrequency] = useState(440);
3 let canvasRef = useRef(null);
4
5 // Callback function for ref, called when ref is assigned or detached
6 const setCanvasRef = useCallback(element => {
7 // element will be null during unmounting
8 if (element) {
9 canvasRef.current = element;
10 // We can now perform initialization after the reference is assigned
11 initializeCanvas(element, frequency);
12 } else {
13 // Cleaning up resources on unmount
14 if (canvasRef.current) {
15 cleanupCanvas(canvasRef.current);
16 }
17 canvasRef.current = null;
18 }
19 }, [frequency]); // Dependency on frequency
20
21 // Function initializing canvas
22 const initializeCanvas = (canvas, freq) => {
23 console.log(`Initializing analyzer for frequency ${freq} Hz`);
24 const ctx = canvas.getContext('2d');
25 // Drawing...
26 };
27
28 return (
29 <div>
30 <canvas
31 ref={setCanvasRef}
32 width="600"
33 height="300"
34 />
35 <input
36 type="range"
37 min="20"
38 max="20000"
39 value={frequency}
40 onChange={e => setFrequency(Number(e.target.value))}
41 />
42 <div>Frequency: {frequency} Hz</div>
43 </div>
44 );
45}Callback ref gives us more control because it's called both when assigning and when removing the reference.
2. Combining useRef with forwardRef
Sometimes we want to pass a reference to a child component. We can do this using forwardRef:
1// Child component
2const NavigationControl = forwardRef((props, ref) => {
3 return (
4 <div className="nav-control">
5 <label>{props.label}</label>
6 <input
7 ref={ref}
8 type="text"
9 className="nav-input"
10 value={props.value}
11 onChange={props.onChange}
12 />
13 </div>
14 );
15});
16
17// Parent component
18function NavigationPanel() {
19 const destinationInputRef = useRef(null);
20 const [destination, setDestination] = useState('');
21
22 const focusDestination = () => {
23 // We can access the inner input thanks to forwardRef
24 destinationInputRef.current.focus();
25 };
26
27 return (
28 <div className="nav-panel">
29 <h2>Navigation Panel</h2>
30
31 <NavigationControl
32 ref={destinationInputRef}
33 label="Destination:"
34 value={destination}
35 onChange={e => setDestination(e.target.value)}
36 />
37
38 <button onClick={focusDestination}>
39 Set destination
40 </button>
41 </div>
42 );
43}forwardRef allows a component to receive a reference from its parent and pass it to a specific element inside the component.
3. Storing multiple references
Sometimes we need to track multiple elements, for example a list of elements:
1function StarMap({ stars }) {
2 // Storing map of references to stars
3 const starRefs = useRef({});
4
5 // Function to scroll to a specific star
6 const scrollToStar = (starId) => {
7 if (starRefs.current[starId]) {
8 starRefs.current[starId].scrollIntoView({
9 behavior: 'smooth',
10 block: 'center'
11 });
12 }
13 };
14
15 return (
16 <div className="star-map-container">
17 <div className="star-list">
18 {stars.map(star => (
19 <div
20 key={star.id}
21 // We save the reference to the element in our map
22 ref={el => starRefs.current[star.id] = el}
23 className="star-item"
24 >
25 <h3>{star.name}</h3>
26 <p>Typ: {star.type}</p>
27 <p>Distance: {star.distance} light years</p>
28 </div>
29 ))}
30 </div>
31
32 <div className="star-navigator">
33 <h3>Quick navigation</h3>
34 {stars.map(star => (
35 <button
36 key={star.id}
37 onClick={() => scrollToStar(star.id)}
38 >
39 {star.name}
40 </button>
41 ))}
42 </div>
43 </div>
44 );
45}In this example, we store a map of references where the key is the star's id and the value is a reference to the corresponding DOM element.
Common pitfalls when using useRef
1. Attempting to render directly from ref.current
Since changing ref.current does not cause a re-render, attempting to use this value directly in JSX can lead to inconsistencies:
1// BAD: Changing ref.current won't cause the interface to update
2function BadCounter() {
3 const countRef = useRef(0);
4
5 const increment = () => {
6 // This change will not cause a re-render
7 countRef.current += 1;
8 console.log(`Counter: ${countRef.current}`); // Will be logged correctly
9 };
10
11 return (
12 <div>
13 <p>Counter: {countRef.current}</p> {/* Won't update after clicking */}
14 <button onClick={increment}>Increment</button>
15 </div>
16 );
17}
18
19// GOOD: Use useState for values that affect rendering
20function GoodCounter() {
21 const [count, setCount] = useState(0);
22
23 const increment = () => {
24 setCount(c => c + 1);
25 };
26
27 return (
28 <div>
29 <p>Counter: {count}</p> {/* Will update after clicking */}
30 <button onClick={increment}>Increment</button>
31 </div>
32 );
33}2. Forgetting about .current
A common mistake is forgetting to access the value through .current:
1// BAD: Brak .current
2function MissionLog({ onAddLog }) {
3 const logInputRef = useRef(null);
4
5 const handleAddLog = () => {
6 // Error: We forgot about .current
7 const logText = logInputRef.value;
8 onAddLog(logText);
9 };
10
11 return (
12 <div>
13 <input ref={logInputRef} type="text" />
14 <button onClick={handleAddLog}>Add entry</button>
15 </div>
16 );
17}
18
19// GOOD: We use .current
20function MissionLog({ onAddLog }) {
21 const logInputRef = useRef(null);
22
23 const handleAddLog = () => {
24 // Correct usage of .current
25 const logText = logInputRef.current.value;
26 onAddLog(logText);
27 logInputRef.current.value = '';
28 };
29
30 return (
31 <div>
32 <input ref={logInputRef} type="text" />
33 <button onClick={handleAddLog}>Add entry</button>
34 </div>
35 );
36}3. Improper use of ref for render control
useRef is not the appropriate tool for controlling when a component should render:
1// BAD: Attempting to use ref to control rendering
2function BadRenderControl() {
3 const shouldUpdateRef = useRef(false);
4
5 const forceUpdate = () => {
6 shouldUpdateRef.current = true;
7 // Missing mechanism to force re-rendering
8 };
9
10 console.log('Rendering',shouldUpdateRef.current);
11
12 // This won't work as expected
13 if (shouldUpdateRef.current) {
14 shouldUpdateRef.current = false;
15 // Some operations...
16 }
17
18 return <button onClick={forceUpdate}>Refresh</button>;
19}
20
21// GOOD: Using useState to control rendering
22function GoodRenderControl() {
23 const [update, setUpdate] = useState(0);
24 const didUpdateRef = useRef(false);
25
26 const forceUpdate = () => {
27 setUpdate(u => u + 1); // Triggers re-rendering
28 };
29
30 console.log('Rendering',update);
31
32 useEffect(() => {
33 if (update > 0) {
34 didUpdateRef.current = true;
35 // Operations after update...
36 }
37 }, [update]);
38
39 return <button onClick={forceUpdate}>Refresh</button>;
40}Best practices with useRef
Use useRef for values that don't affect rendering - if a value change should cause an interface update, use
useState.Be cautious with direct DOM manipulation - DOM manipulation through references should be limited and well thought out.
Initialize refs with appropriate initial values - for example
nullfor DOM references or initial values for counters.Check if ref.current exists before using it - especially for DOM references that may be
nullduring the first render.Use useCallback for ref-creating functions - if you're passing a reference function, consider wrapping it in
useCallbackfor optimization.Avoid overusing refs - although refs are useful, over-relying on them can lead to hard-to-maintain code.
Practical example: Advanced mission video player
Below is a more complex example that demonstrates various aspects of using useRef:
1import React, { useState, useRef, useEffect, useCallback } from 'react';
2
3function MissionVideoPlayer({ videoUrl, onProgress }) {
4 const [isPlaying, setIsPlaying] = useState(false);
5 const [duration, setDuration] = useState(0);
6 const [currentTime, setCurrentTime] = useState(0);
7 const [volume, setVolume] = useState(0.7);
8
9 // References
10 const videoRef = useRef(null); // Reference to video element
11 const progressBarRef = useRef(null); // Reference to progress bar
12 const animationFrameRef = useRef(null); // requestAnimationFrame ID for updating time
13 const isMountedRef = useRef(true); // Flag indicating whether the component is mounted
14 const lastUpdateTimeRef = useRef(0); // Time of the last update for throttling
15
16 // Function initializing video metadata
17 const handleLoadedMetadata = () => {
18 if (videoRef.current) {
19 setDuration(videoRef.current.duration);
20 videoRef.current.volume = volume;
21 }
22 };
23
24 // Function updating progress bar
25 const updateProgressBar = useCallback(() => {
26 if (!videoRef.current || !isMountedRef.current) return;
27
28 const now = Date.now();
29 if (now - lastUpdateTimeRef.current > 200) { // Throttling to 5 updates per second
30 setCurrentTime(videoRef.current.currentTime);
31 onProgress(videoRef.current.currentTime);
32 lastUpdateTimeRef.current = now;
33 }
34
35 // Continue updating if video is playing
36 if (videoRef.current.paused) return;
37 animationFrameRef.current = requestAnimationFrame(updateProgressBar);
38 }, [onProgress]);
39
40 // Start or pause playback
41 const togglePlayPause = () => {
42 if (!videoRef.current) return;
43
44 if (videoRef.current.paused) {
45 videoRef.current.play();
46 setIsPlaying(true);
47 animationFrameRef.current = requestAnimationFrame(updateProgressBar);
48 } else {
49 videoRef.current.pause();
50 setIsPlaying(false);
51 if (animationFrameRef.current) {
52 cancelAnimationFrame(animationFrameRef.current);
53 }
54 }
55 };
56
57 // Changing playback position after clicking progress bar
58 const handleProgressBarClick = (e) => {
59 if (!progressBarRef.current || !videoRef.current) return;
60
61 const rect = progressBarRef.current.getBoundingClientRect();
62 const position = (e.clientX - rect.left) / rect.width;
63 const newTime = duration * Math.max(0, Math.min(1, position));
64
65 videoRef.current.currentTime = newTime;
66 setCurrentTime(newTime);
67 };
68
69 // Changing volume
70 const handleVolumeChange = (e) => {
71 const newVolume = parseFloat(e.target.value);
72 setVolume(newVolume);
73
74 if (videoRef.current) {
75 videoRef.current.volume = newVolume;
76 }
77 };
78
79 // Effect cleaning up animationFrame and setting mounting flag
80 useEffect(() => {
81 return () => {
82 isMountedRef.current = false;
83 if (animationFrameRef.current) {
84 cancelAnimationFrame(animationFrameRef.current);
85 }
86 };
87 }, []);
88
89 // Formatting time (mm:ss)
90 const formatTime = (timeInSeconds) => {
91 const minutes = Math.floor(timeInSeconds / 60);
92 const seconds = Math.floor(timeInSeconds % 60);
93 return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
94 };
95
96 return (
97 <div className="mission-video-player">
98 <video
99 ref={videoRef}
100 src={videoUrl}
101 onLoadedMetadata={handleLoadedMetadata}
102 onEnded={() => setIsPlaying(false)}
103 />
104
105 <div className="controls">
106 <button onClick={togglePlayPause}>
107 {isPlaying ? 'Pause' : 'Play'}
108 </button>
109
110 <div className="time-display">
111 {formatTime(currentTime)} / {formatTime(duration)}
112 </div>
113
114 <div
115 ref={progressBarRef}
116 className="progress-bar"
117 onClick={handleProgressBarClick}
118 >
119 <div
120 className="progress-fill"
121 style={{ width: `${(currentTime / duration) * 100}%` }}
122 />
123 </div>
124
125 <div className="volume-control">
126 <label>Volume:</label>
127 <input
128 type="range"
129 min="0"
130 max="1"
131 step="0.05"
132 value={volume}
133 onChange={handleVolumeChange}
134 />
135 </div>
136 </div>
137 </div>
138 );
139}This example demonstrates several advanced aspects of working with useRef:
Multiple different uses of references:
- Access to DOM element (
videoRef,progressBarRef) - Storing animation ID (
animationFrameRef) - Mounting flag (
isMountedRef) - Tracking values for throttling (
lastUpdateTimeRef)
- Access to DOM element (
Integration of references with effects and callbacks
Direct manipulation of the video element through its API
Throttling state updates using time references
Summary
The useRef hook is an essential tool in the React toolkit, particularly useful for:
- Storing references to DOM elements
- Maintaining values between renders without triggering re-rendering
- Tracking previous values
- Storing timer, interval, and requestAnimationFrame IDs
- Storing flags and values that don't directly affect the interface
The key to effectively using useRef is understanding when to use it instead of useState. The fundamental difference is that useRef does not cause a re-render when its value changes, making it the ideal choice for operations that shouldn't affect the rendering cycle.
On our cosmic journey through React, useRef is like a storage compartment on the ship - a place where you can store things you need to have on hand, but that don't require the attention of the entire crew every time they change.
Code for this lesson: App.jsx
1import React, { useState, useRef, useEffect } from 'react';
2
3// useRef for storing references to DOM elements
4function DOMReferenceDemo() {
5 const inputRef = useRef(null);
6 const canvasRef = useRef(null);
7
8 const focusInput = () => {
9 inputRef.current?.focus();
10 };
11
12 const drawOnCanvas = () => {
13 const canvas = canvasRef.current;
14 if (!canvas) return;
15
16 const ctx = canvas.getContext('2d');
17 ctx.clearRect(0, 0, canvas.width, canvas.height);
18
19 // Drawing stars
20 for (let i = 0; i < 50; i++) {
21 const x = Math.random() * canvas.width;
22 const y = Math.random() * canvas.height;
23 const radius = Math.random() * 2;
24
25 ctx.beginPath();
26 ctx.arc(x, y, radius, 0, Math.PI * 2);
27 ctx.fillStyle = `rgba(255, 255, 255, ${Math.random()})`;
28 ctx.fill();
29 }
30
31 // Drawing a planet
32 ctx.beginPath();
33 ctx.arc(canvas.width / 2, canvas.height / 2, 30, 0, Math.PI * 2);
34 ctx.fillStyle = '#61dafb';
35 ctx.fill();
36 };
37
38 return (
39 <div className="demo-card">
40 <h2>DOM References</h2>
41
42 <div className="input-section">
43 <input ref={inputRef} type="text" placeholder="Click the button below" />
44 <button onClick={focusInput}>Focus the input</button>
45 </div>
46
47 <div className="canvas-section">
48 <canvas ref={canvasRef} width={280} height={150} />
49 <button onClick={drawOnCanvas}>Draw space</button>
50 </div>
51 </div>
52 );
53}
54
55// useRef for storing values between renders
56function PreviousValueDemo() {
57 const [count, setCount] = useState(0);
58 const prevCountRef = useRef(0);
59
60 useEffect(() => {
61 prevCountRef.current = count;
62 });
63
64 return (
65 <div className="demo-card">
66 <h2>Previous value</h2>
67 <div className="values">
68 <div className="value-box">
69 <span className="label">Current:</span>
70 <span className="number current">{count}</span>
71 </div>
72 <div className="value-box">
73 <span className="label">Previous:</span>
74 <span className="number previous">{prevCountRef.current}</span>
75 </div>
76 </div>
77 <button onClick={() => setCount(c => c + 1)}>Increase</button>
78 </div>
79 );
80}
81
82// useRef for measuring elements
83function MeasurementDemo() {
84 const boxRef = useRef(null);
85 const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
86 const [boxSize, setBoxSize] = useState(100);
87
88 const measureBox = () => {
89 if (boxRef.current) {
90 const rect = boxRef.current.getBoundingClientRect();
91 setDimensions({ width: rect.width, height: rect.height });
92 }
93 };
94
95 return (
96 <div className="demo-card">
97 <h2>Element measurements</h2>
98 <div
99 ref={boxRef}
100 className="measure-box"
101 style={{ width: boxSize, height: boxSize }}
102 >
103 {boxSize}x{boxSize}
104 </div>
105 <div className="measurement-info">
106 Measured: {dimensions.width.toFixed(0)} x {dimensions.height.toFixed(0)}
107 </div>
108 <div className="controls">
109 <button onClick={() => setBoxSize(s => Math.max(50, s - 20))}></button>
110 <button onClick={measureBox}>Measure</button>
111 <button onClick={() => setBoxSize(s => Math.min(200, s + 20))}></button>
112 </div>
113 </div>
114 );
115}
116
117// useRef for storing timeouts/intervals
118function TimerRefDemo() {
119 const [time, setTime] = useState(0);
120 const [isRunning, setIsRunning] = useState(false);
121 const intervalRef = useRef(null);
122
123 const start = () => {
124 if (intervalRef.current) return;
125
126 setIsRunning(true);
127 intervalRef.current = setInterval(() => {
128 setTime(t => t + 1);
129 }, 100);
130 };
131
132 const stop = () => {
133 if (intervalRef.current) {
134 clearInterval(intervalRef.current);
135 intervalRef.current = null;
136 }
137 setIsRunning(false);
138 };
139
140 const reset = () => {
141 stop();
142 setTime(0);
143 };
144
145 // Cleanup on unmount
146 useEffect(() => {
147 return () => {
148 if (intervalRef.current) {
149 clearInterval(intervalRef.current);
150 }
151 };
152 }, []);
153
154 const formatTime = (t) => {
155 const seconds = Math.floor(t / 10);
156 const decimals = t % 10;
157 return `${seconds}.${decimals}s`;
158 };
159
160 return (
161 <div className="demo-card">
162 <h2>⏱Timer with useRef</h2>
163 <div className="timer-display">{formatTime(time)}</div>
164 <div className="controls">
165 <button onClick={start} disabled={isRunning}>▶Start</button>
166 <button onClick={stop} disabled={!isRunning}>⏸Pause</button>
167 <button onClick={reset}>Reset</button>
168 </div>
169 <p className="hint">Interval ID stored in useRef</p>
170 </div>
171 );
172}
173
174function App() {
175 return (
176 <div className="app">
177 <h1>useRef Hook</h1>
178 <p className="subtitle">References and values outside the render cycle</p>
179 <div className="demos">
180 <DOMReferenceDemo />
181 <PreviousValueDemo />
182 <MeasurementDemo />
183 <TimerRefDemo />
184 </div>
185 </div>
186 );
187}
188
189export default App;Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What does the dependency array in useEffect contain?
2. Which of the following is an example of a side effect in React?
Hands-on tasks in the game
- Horizontal ordering
Arrange the useRef declaration elements from left to right:
- Vertical ordering
Order the steps for correctly using async/await inside useEffect:
- Click in order
Arrange async operations in useEffect:
- Code editor
Geolocation Position Tracking