React Hooks

User Avatar

In React 16.8, Hooks were introduced as new APIs that revolutionized functional components in React. These functions empower functional components to utilize the features previously exclusive to class components, resulting in a more streamlined and cohesive way to combine the two.


Prior to Hooks, functional and class components in React had distinct roles. Functional components focused solely on rendering data to the UI and accepting props from parent components, usually class components. They lacked the ability to manage internal state or understand the component lifecycle, earning them the label of "dumb components."


In contrast, class components could maintain their own internal state and leverage lifecycle methods to perform operations at different phases. This included tasks like fetching data from external APIs upon mounting, updating state based on user interactions, and unsubscribing from stores when unmounting. Class components were known as "smart components" due to their ability to handle complex logic.


However, class components introduced certain issues, some of which were inherent to JavaScript's class-based design. React Hooks were introduced to address these problems and provide a more elegant solution. They offer functional components the ability to manage state, handle side effects, and utilize lifecycle-like functionality.


Hooks are not directly tied to React itself but rather provide a way to enhance functional components by leveraging JavaScript's function-based nature. By using Hooks, developers can now create functional components that have access to state management, lifecycle-related capabilities, and other advanced React features.


In summary, Hooks in React 16.8 enable functional components to harness the power of React's class components, enabling them to handle complex functionality in a more concise and cohesive manner.

Challenges of React Class Components

In React class components, there are several issues inherited from JavaScript classes that can make the code more complex and prone to bugs. Let's discuss each of these issues with examples.


1. Autobinding and Working with `this`:

In class components, you need to explicitly bind the `this` context for custom methods or event handlers. Failure to bind `this` can result in incorrect function invocation or loss of context. Here's an example:

class Card extends React.Component {
 constructor(props) {
  super(props);
  this.state = { name: "John Doe" };
  this.changeName = this.changeName.bind(this);
 }

 changeName() {
  this.setState({ name: "Jane Doe" });
 }

 render() {
  return (
   <div>
    <p>My name is {this.state.name}.</p>
    <button onClick={this.changeName}>Change Name</button>
   </div>
  );
 }
}

2. Verbose Syntax:

Class components often lead to large components with complex logic spread across multiple lifecycle methods, resulting in verbose and hard-to-follow code. Related logic needs to be repeated across different lifecycle methods. Here's an example:

class FriendProfile extends React.Component {
 constructor(props) {
  super(props);
  this.state = {
   loading: false,
   friend: {}
  };
 }

 componentDidMount() {
  this.subscribeToFriendsStatus(this.props.id);
  this.updateFriendProfile(this.props.id);
 }

 componentDidUpdate(prevProps) {
  if (prevProps.id !== this.props.id) {
   this.updateFriendProfile(this.props.id);
  }
 }

 componentWillUnmount() {
  this.unsubscribeFromFriendsStatus(this.props.id);
 }

 subscribeToFriendsStatus() {
  console.log("I have subscribed");
 }

 unsubscribeFromFriendsStatus() {
  console.log("I have unsubscribed");
 }

 fetchFriendData(id) {
  // fetch friend logic here
 }

 async updateFriendProfile(id) {
  this.setState({ loading: true });
  await this.fetchFriendData(id);
  this.setState({ loading: false });
 }

 render() {
  return <div>Hello {this.friend ? this.friend.name : "John Doe!"}</div>;
 }
}

Both of these issues can make the code harder to understand, maintain, and debug. React Hooks offer a solution to these problems by allowing functional components to handle state, side effects, and lifecycle-like behavior in a more concise and intuitive way.

Difficult to Reuse and Share Logic

Composing React class components using Higher-Order Components (HOCs) can lead to code that is difficult to read and maintain, especially when multiple HOCs are involved. Let's illustrate this with an example.


Consider the following HOCs: `withRouter`, `withAuth`, `withLogger`, and `withTheme`. Each HOC provides additional functionality to the component it wraps. Now, let's compose these HOCs together to enhance a component:

import React from "react";
import withRouter from "./components/withRouter";
import withAuth from "./components/withAuth";
import withLogger from "./components/withLogger";
import withTheme from "./components/withTheme";

const SomeComponent = (props) => {
 return (
  // JSX of SomeComponent
 );
};

export default withTheme(
 withAuth(
  withLogger(
   withRouter(SomeComponent)
  )
 )
);


As you can see, the component hierarchy becomes deeply nested due to the composition of multiple HOCs. This nesting not only makes the code harder to read but also affects the React DevTools, making it challenging to navigate through the component state and props during debugging.


This pattern can result in code that is difficult to reason about and maintain, especially as the number of HOCs and their complexity grows.


React Hooks provide a more straightforward alternative to composing components, allowing you to handle state, context, and side effects in a more readable and intuitive way without the need for HOCs.

How Hooks Can Help

Hooks solve the class-related problems by providing cleaner, leaner, and more maintainable code. Let's dive into the details of some commonly used React Hooks.


The useState Hook allows you to manage state in functional components. It takes the initial state as an argument and returns an array with two values: the current state and a function to update the state. By using array destructuring, you can easily access and update the state. Here's an example:

import React, { useState } from "react";

const Card = () => {
 const [name, setName] = useState("John Doe");

 return (
  <div>
   <p>Hello, from Card. My name is {name}</p>
   <button onClick={() => setName("Jane Doe")}>Change Name</button>
  </div>
 );
};

export default Card;


The useEffect Hook simplifies handling component lifecycles and side effects. It takes a function as its first argument, which will be executed after each complete render. You can perform cleanup actions by returning a function from the useEffect Hook. The second argument is an array of dependencies, and the effect will re-run whenever any of the dependencies change. Here's an example:

import React, { useState, useEffect } from "react";

function FriendProfile({ id }) {
 const [loading, setLoading] = useState(false);
 const [friend, setFriend] = useState({});

 useEffect(() => {
  // componentDidMount and componentDidUpdate logic
  updateFriendProfile(id);
  subscribeToFriendsStatus(id);

  return () => {
   // componentWillUnmount logic
   unSubscribeToFriendsStatus(id);
  };
 }, [id]);

 const subscribeToFriendsStatus = () => {
  console.log("I have subscribed");
 };

 const unSubscribeToFriendsStatus = () => {
  console.log("I have unsubscribed");
 };

 const fetchFriendData = (id) => {
  // fetch friend logic here
 };

 const updateFriendProfile = async (id) => {
  setLoading(true);

  // fetch friend data
  await fetchFriendData(id);

  setLoading(false);
 };

 return <div> Hello {friend ? friend.name : "John Doe!"}</div>; // ... jsx
}

export default FriendProfile;

In the example above, the useEffect Hook is used to handle the lifecycle methods `componentDidMount` and `componentDidUpdate`. The effect runs when the `id` prop changes, and it performs the necessary operations. The returned cleanup function takes care of the `componentWillUnmount` logic.


By utilizing the useState and useEffect Hooks, you can achieve similar functionality as class components but with cleaner and more concise code. Additionally, Hooks provide a way to tackle other scenarios like accessing and updating DOM elements using useRef and sharing state across components using useContext. Custom Hooks allow you to encapsulate reusable logic and create more modular code in your React applications.

Custom Hooks: Hooks Patterns for Sharing Non-Visual Logic

Custom Hooks are a powerful way to share non-visual logic and keep your code DRY (Don't Repeat Yourself). They allow you to encapsulate reusable logic and use it across multiple components. Let's explore some commonly used Hooks in more detail.

The `useIsMounted` custom Hook you provided is a good example. It helps track the mounted status of a component, allowing you to avoid state updates on unmounted components. By creating this custom Hook, you can reuse it in multiple components to handle the mounted status. Here's an example usage:

import { useEffect, useState } from "react";

const useIsMounted = () => {
 const [isMounted, setIsMounted] = useState(false);

 useEffect(() => {
  setIsMounted(true);

  return () => {
   setIsMounted(false);
  };
 }, []);

 return isMounted;
};

export default useIsMounted;

You can then use the `useIsMounted` Hook in your component:

import React, { useEffect, useState } from "react";
import useIsMounted from "./useIsMounted";

const Dev = () => {
 const isMounted = useIsMounted();
 const [state, setState] = useState("");

 useEffect(() => {
  function someFunc() {
   setTimeout(() => {
    if (isMounted) {
     setState("Lawrence Eagles");
    }
   }, 4000);
  }

  someFunc();
 }, [isMounted]);

 return (
  // ... JSX code
 );
};

The `useRef` Hook is another useful Hook that allows you to create a mutable ref object. This is particularly handy when you need direct access to DOM elements or when you want to persist a mutable value across component renders. Here's an example:

import React, { useRef } from "react";

const FormComponent = () => {
 const inputElem = useRef(null);

 const onButtonClick = () => {
  inputElem.current.focus();
 };

 return (
  <>
   <input ref={inputElem} type="text" />
   <button onClick={onButtonClick}>Focus the input</button>
  </>
 );
};

In this example, the `inputElem` ref is used to access the input element and call the `focus()` method when the button is clicked.

The `useContext` Hook allows you to access the value of a context object from a functional component without prop drilling. It takes the context object returned from `React.createContext` as its parameter and returns the current context value. Here's an example:

import React, { createContext, useContext } from "react";

const themes = {
 light: {
  name: "Light",
  foreground: "#000000",
  background: "#eeeeee"
 },
 dark: {
  name: "Dark",
  foreground: "#ffffff",
  background: "#222222"
 }
};

const ThemeContext = createContext(themes.light);

function App() {
 return (
  <ThemeContext.Provider value={themes.dark}>
   <Button />
  </ThemeContext.Provider>
 );
}

const Button = () => {
 const theme = useContext(ThemeContext);

 return (
  <button style={{ background: theme.background, color: theme.foreground }}>
   {theme.name} Button
  </button>
 );
};


In this example, the `Button` component uses the `useContext` Hook to access the current value of the `ThemeContext` and apply it to the button's style.

By leveraging custom Hooks like `useIsMounted`, `useRef`, `useContext`, and other built-in Hooks like `useState` and `useEffect`, you can create cleaner, more reusable, and maintainable code

Challenges with React Hooks And How To Overcome Them

Handling Stale State:

To address the stale state problem, you can use the updater function form of the `useState` Hook. By passing a function to `setCount` that receives the previous state value as an argument, you can ensure that the state update is based on the latest state. Here's the updated code:

import React, { useState } from "react";

const Counter = () => {
 const [count, setCount] = useState(0);

 const lazyUpdate = () => {
  setTimeout(() => {
   setCount(prevCount => prevCount + 1);
  }, 3000);
 };

 return (
  <div>
   <p>
    <strong>You clicked {count} times</strong>
   </p>
   <button onClick={lazyUpdate}>Increment count</button>
  </div>
 );
};

export default Counter;

Now, when you click the "Increment count" button multiple times, the count will increase correctly because the updater function ensures that the state is based on the latest value.


Accessing State in an Asynchronous Callback:

When you want to access state in an asynchronous callback, such as in the `openModal` function in your example, you can use the `useRef` Hook to create a mutable reference to the state value. By using a ref, you can access the current value of the state without relying on closures. Here's the updated code:

import React, { useState, useRef } from "react";

const AsyncCounter = () => {
 const counterRef = useRef(0);
 const [count, setCount] = useState(0);

 const handleIncrement = () => {
  counterRef.current++;
  setCount(count + 1);
 };

 const handleAlertClick = () => {
  setTimeout(() => {
   alert("You clicked on: " + counterRef.current);
  }, 3000);
 };

 return (
  <div>
   <p>You clicked {count} times</p>
   <button onClick={handleIncrement}>Click me</button>
   <button onClick={handleAlertClick}>Show alert</button>
  </div>
 );
};

export default AsyncCounter;

By using the `counterRef.current` value instead of `count` in the `handleAlertClick` function, you ensure that the correct value is displayed even if the state has changed during the delay.


Accessing State Synchronously:

When you need to access the state synchronously, such as computing a new value based on the current state, you can calculate the new value first and then update both states together. This ensures that the computed value is based on the updated state. Here's the updated code:

import React, { useState } from "react";

const SyncCounter = () => {
 const [count, setCount] = useState(0);
 const [currentCount, setCurrentCount] = useState("");

 const increment = () => {
  const newCount = count + 1;
  setCount(newCount);
  setCurrentCount(`computed count is ${newCount}`);
 };

 const decrement = () => {
  const newCount = count - 1;
  setCount(newCount);
  setCurrentCount(`computed count is ${newCount}`);
 };

 return (
  <div className="App">
   <h1>Update Count!</h1>
   <p>Count: {count}</p>
   <p>{currentCount}</p>
   <button type="button" onClick={increment}>
    Add
   </button>
   <button type="button" onClick={decrement}>
    Subtract
   </button>
  </div>
 );
};

export default SyncCounter;

Conclusion

As we discussed earlier, Hooks are a collection of specialized JavaScript functions that aim to solve the issues you may experience when working with React class components. They enable functional components to use React features only available with React classes by giving you direct and flexible access to these features. Clearly, Hooks have changed the way React components are created for the better—and are here to stay!




142 Comments
People Image
plPbFTDX

SmjDxwhzyCbTe

Commented on:
People Image
plPbFTDX

SmjDxwhzyCbTe

Commented on:
People Image
plPbFTDX

SmjDxwhzyCbTe

Commented on:
People Image
HDiPxbBOEAXcGk

KpFLQejfmyAbC

Commented on:
People Image
HDiPxbBOEAXcGk

KpFLQejfmyAbC

Commented on:
People Image
HDiPxbBOEAXcGk

KpFLQejfmyAbC

Commented on:
People Image
wMkKruxanSTHZl

QExsIclo

Commented on:
People Image
wMkKruxanSTHZl

QExsIclo

Commented on:
People Image
wMkKruxanSTHZl

QExsIclo

Commented on:
People Image
yaLxKAQRICu

EbsSxZufVdz

Commented on:
People Image
yaLxKAQRICu

EbsSxZufVdz

Commented on:
People Image
yaLxKAQRICu

EbsSxZufVdz

Commented on:
People Image
GKJFkcoT

tlJWpciAu

Commented on:
People Image
GKJFkcoT

tlJWpciAu

Commented on:
People Image
GKJFkcoT

tlJWpciAu

Commented on:
People Image
YvwjKLdzx

UgIBcWoqXREr

Commented on:
People Image
YvwjKLdzx

UgIBcWoqXREr

Commented on:
People Image
YvwjKLdzx

UgIBcWoqXREr

Commented on:
People Image
PzIosEHYKkftyBTn

UvpgaKBiGw

Commented on:
People Image
PzIosEHYKkftyBTn

UvpgaKBiGw

Commented on:
People Image
PzIosEHYKkftyBTn

UvpgaKBiGw

Commented on:
People Image
vIHRVzSKqZUyYL

PQHpgtxNLaJo

Commented on:
People Image
vIHRVzSKqZUyYL

PQHpgtxNLaJo

Commented on:
People Image
vIHRVzSKqZUyYL

PQHpgtxNLaJo

Commented on:
People Image
gLhkCrjT

CZdYsaPftbeo

Commented on:
People Image
gLhkCrjT

CZdYsaPftbeo

Commented on:
People Image
gLhkCrjT

CZdYsaPftbeo

Commented on:
People Image
TjIfZKlt

YBWwAXiZhq

Commented on:
People Image
TjIfZKlt

YBWwAXiZhq

Commented on:
People Image
TjIfZKlt

YBWwAXiZhq

Commented on:
People Image
SVHgjLJrkfnNUEMu

YiWUltRba

Commented on:
People Image
SVHgjLJrkfnNUEMu

YiWUltRba

Commented on:
People Image
SVHgjLJrkfnNUEMu

YiWUltRba

Commented on:
People Image
VSdLQwKOEZBl

WxKgkpdjVeLv

Commented on:
People Image
VSdLQwKOEZBl

WxKgkpdjVeLv

Commented on:
People Image
VSdLQwKOEZBl

WxKgkpdjVeLv

Commented on:
People Image
ieLwfVGDbgtaOJ

BzbqEhuvt

Commented on:
People Image
ieLwfVGDbgtaOJ

BzbqEhuvt

Commented on:
People Image
ieLwfVGDbgtaOJ

BzbqEhuvt

Commented on:
People Image
YQUGtAMT

JjRePNVKbBLhlfHY

Commented on:
People Image
YQUGtAMT

JjRePNVKbBLhlfHY

Commented on:
People Image
YQUGtAMT

JjRePNVKbBLhlfHY

Commented on:
People Image
FlWfVMwUzoh

YBxOFRQs

Commented on:
People Image
FlWfVMwUzoh

YBxOFRQs

Commented on:
People Image
FlWfVMwUzoh

YBxOFRQs

Commented on:
People Image
RimOuXQnKANyPqdD

OCiaGdUeEzsDPo

Commented on:
People Image
RimOuXQnKANyPqdD

OCiaGdUeEzsDPo

Commented on:
People Image
RimOuXQnKANyPqdD

OCiaGdUeEzsDPo

Commented on:
People Image
PLpUSFzD

qmOgkcdbueW

Commented on:
People Image
PLpUSFzD

qmOgkcdbueW

Commented on:
People Image
PLpUSFzD

qmOgkcdbueW

Commented on:
People Image
YFjrtZDKGQ

tTaxYQGMznvNh

Commented on:
People Image
YFjrtZDKGQ

tTaxYQGMznvNh

Commented on:
People Image
YFjrtZDKGQ

tTaxYQGMznvNh

Commented on:
People Image
jZxrftOauWz

wyaeuScG

Commented on:
People Image
jZxrftOauWz

wyaeuScG

Commented on:
People Image
jZxrftOauWz

wyaeuScG

Commented on:
People Image
vXZxdzuDgP

rDsmaGSeckfHvWXg

Commented on:
People Image
vXZxdzuDgP

rDsmaGSeckfHvWXg

Commented on:
People Image
vXZxdzuDgP

rDsmaGSeckfHvWXg

Commented on:
People Image
DtazoQKe

tEFQuaRNZCKrG

Commented on:
People Image
DtazoQKe

tEFQuaRNZCKrG

Commented on:
People Image
DtazoQKe

tEFQuaRNZCKrG

Commented on:
People Image
fwlCOGoA

LSsvCTZRGhdH

Commented on:
People Image
fwlCOGoA

LSsvCTZRGhdH

Commented on:
People Image
fwlCOGoA

LSsvCTZRGhdH

Commented on:
People Image
XAJgaofuktwHCj

soaZCMVkFyhzdtfR

Commented on:
People Image
XAJgaofuktwHCj

soaZCMVkFyhzdtfR

Commented on:
People Image
XAJgaofuktwHCj

soaZCMVkFyhzdtfR

Commented on:
People Image
yJcOvbQG

DHzbZCMnRLmFo

Commented on:
People Image
yJcOvbQG

DHzbZCMnRLmFo

Commented on:
People Image
yJcOvbQG

DHzbZCMnRLmFo

Commented on:
People Image
CaegRUEBIQrbT

eDnahbjmPf

Commented on:
People Image
CaegRUEBIQrbT

eDnahbjmPf

Commented on:
People Image
CaegRUEBIQrbT

eDnahbjmPf

Commented on:
People Image
exTpsGJMRqjLHw

rowEyZtUVFbmAcRP

Commented on:
People Image
exTpsGJMRqjLHw

rowEyZtUVFbmAcRP

Commented on:
People Image
exTpsGJMRqjLHw

rowEyZtUVFbmAcRP

Commented on:
People Image
cHDYhusfAiakPnSl

GwWQnaMyjOvfYd

Commented on:
People Image
cHDYhusfAiakPnSl

GwWQnaMyjOvfYd

Commented on:
People Image
cHDYhusfAiakPnSl

GwWQnaMyjOvfYd

Commented on:
People Image
euAUmJXDOwZ

FRyBMtxCuzWav

Commented on:
People Image
euAUmJXDOwZ

FRyBMtxCuzWav

Commented on:
People Image
euAUmJXDOwZ

FRyBMtxCuzWav

Commented on:
People Image
fzQdNysOrYjL

PhazsnvrNOADXYGB

Commented on:
People Image
fzQdNysOrYjL

PhazsnvrNOADXYGB

Commented on:
People Image
fzQdNysOrYjL

PhazsnvrNOADXYGB

Commented on:
People Image
VKDBYWRwLFvq

bUPyxJHnX

Commented on:
People Image
VKDBYWRwLFvq

bUPyxJHnX

Commented on:
People Image
VKDBYWRwLFvq

bUPyxJHnX

Commented on:
People Image
aJHSNdnlGLBFpmg

WpslxHjB

Commented on:
People Image
aJHSNdnlGLBFpmg

WpslxHjB

Commented on:
People Image
aJHSNdnlGLBFpmg

WpslxHjB

Commented on:
People Image
smYCwuSTVhNv

okpZEanCYrscW

Commented on:
People Image
smYCwuSTVhNv

okpZEanCYrscW

Commented on:
People Image
smYCwuSTVhNv

okpZEanCYrscW

Commented on:
People Image
SiltLjAORbukM

zjNFgnwKUHxrW

Commented on:
People Image
SiltLjAORbukM

zjNFgnwKUHxrW

Commented on:
People Image
SiltLjAORbukM

zjNFgnwKUHxrW

Commented on:
People Image
dfstvALW

FXpSxTEIahrHsWR

Commented on:
People Image
dfstvALW

FXpSxTEIahrHsWR

Commented on:
People Image
dfstvALW

FXpSxTEIahrHsWR

Commented on:
People Image
IuFAEmjHxU

dreXJKNCiQoPDUlx

Commented on:
People Image
IuFAEmjHxU

dreXJKNCiQoPDUlx

Commented on:
People Image
IuFAEmjHxU

dreXJKNCiQoPDUlx

Commented on:
People Image
gxMviCkjZV

CSdXiZafbMxYhI

Commented on:
People Image
gxMviCkjZV

CSdXiZafbMxYhI

Commented on:
People Image
gxMviCkjZV

CSdXiZafbMxYhI

Commented on:
People Image
vbpSsJNLWkt

XWgIhdExjPbirq

Commented on:
People Image
vbpSsJNLWkt

XWgIhdExjPbirq

Commented on:
People Image
vbpSsJNLWkt

XWgIhdExjPbirq

Commented on:
People Image
ZLAjtBlGVeTQ

xkrsiaDh

Commented on:
People Image
ZLAjtBlGVeTQ

xkrsiaDh

Commented on:
People Image
ZLAjtBlGVeTQ

xkrsiaDh

Commented on:
People Image
TUfXLasvGV

kFiNlRCXrxWsd

Commented on:
People Image
TUfXLasvGV

kFiNlRCXrxWsd

Commented on:
People Image
TUfXLasvGV

kFiNlRCXrxWsd

Commented on:
People Image
tPmrRdlfZWJSjVTD

tufPqBXe

Commented on:
People Image
tPmrRdlfZWJSjVTD

tufPqBXe

Commented on:
People Image
tPmrRdlfZWJSjVTD

tufPqBXe

Commented on:
People Image
SsKYTGQnox

CWRTSfsAvrVu

Commented on:
People Image
SsKYTGQnox

CWRTSfsAvrVu

Commented on:
People Image
SsKYTGQnox

CWRTSfsAvrVu

Commented on:
People Image
DqMkJEplhmQIHW

nzIJxTSyBLYOoU

Commented on:
People Image
DqMkJEplhmQIHW

nzIJxTSyBLYOoU

Commented on:
People Image
DqMkJEplhmQIHW

nzIJxTSyBLYOoU

Commented on:
People Image
dqjYAbcZTCuEU

nxRhCUzPGFsw

Commented on:
People Image
dqjYAbcZTCuEU

nxRhCUzPGFsw

Commented on:
People Image
dqjYAbcZTCuEU

nxRhCUzPGFsw

Commented on:
People Image
yLOtQmIwkc

fYSUiIvlJLWaKsCb

Commented on:
People Image
yLOtQmIwkc

fYSUiIvlJLWaKsCb

Commented on:
People Image
yLOtQmIwkc

fYSUiIvlJLWaKsCb

Commented on:
People Image
rezImFQO

AlUIvmLwJPtn

Commented on:
People Image
rezImFQO

AlUIvmLwJPtn

Commented on:
People Image
rezImFQO

AlUIvmLwJPtn

Commented on:
People Image
35.01hst96ewjn2n7v47xyv87k7vg@mail4u.pw

vel dignissimos magni beatae ab aspernatur a. odio quia ut eligendi sit sint vero dignissimos et autem velit vitae. officia laboriosam enim et vero similique et voluptas nihil numquam. quasi veniam ut

Commented on:
People Image
nqabmPJZtTdl

zsoWBrbAkuEtFT

Commented on:
People Image
nqabmPJZtTdl

zsoWBrbAkuEtFT

Commented on:
People Image
nqabmPJZtTdl

zsoWBrbAkuEtFT

Commented on:
People Image
bdEtFADPTaupHCy

sPDHidCQYxf

Commented on:
People Image
bdEtFADPTaupHCy

sPDHidCQYxf

Commented on:
People Image
bdEtFADPTaupHCy

sPDHidCQYxf

Commented on:
LEAVE YOUR COMMENT