Understanding React Components: Event Handlers, Lifecycle Methods, State Management, and Props Communication

Custom Functions in React

Event Handler Naming Conventions

React uses camelCase for event names. The HTML onclick becomes onClick, and onchange becomes onChange.

Basic Click Events

When attaching event handlers, avoid parentheses—adding () immediately invokes the function:

import React, { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClick() {
    console.log('Button clicked');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

Accessing the Event Object

Custom event handlers receive the event object as a default parameter:

import React, { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClick(event) {
    console.log('Button clicked', event);
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

Handling this Context in Event Handlers

The this keyword is undefined inside custom methods. Bind this in the constructor:

import React, { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log('Button clicked', this);
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

Inline Binding (Alternative Approach)

Bind this directly in the render method:

import React, { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClick() {
    console.log('Button clicked', this);
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>Click Me</button>
      </div>
    );
  }
}

Passing Arguments to Event Handlers

Use .bind() to pass custom arguments alongside the event object:

import React, { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClick(message) {
    console.log('Button clicked', this);
    console.log(message);
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this, 'Custom message')}>
          Click Me
        </button>
      </div>
    );
  }
}

Component Lifecycle Methods

Comparison with Vue

Vue Lifecycle React Lifecycle
created constructor
mounted componentDidMount
updated componentDidUpdate
beforeDestroy componentWillUnmount

Legacy Lifecycle Hooks (Deprecated in React 16.3+)

Initialization Phase

  • constructor(props) — Initialize state and bind methods
  • componentWillMount() — Legacy method, deprecated
  • render() — Required method for rendering UI
  • componentDidMount() — Fetch data, manipulate DOM, equivalent to Vue's mounted

Update Phase

  • componentWillReceiveProps(nextProps) — Legacy method, deprecated
  • shouldComponentUpdate(nextProps, nextState) — Returns boolean, crucial for performance optimization
  • componentWillUpdate() — Legacy method, deprecated
  • render() — Re-renders the view
  • componentDidUpdate() — DOM operations, avoid data fetching here

Destruction Phase

  • componentWillUnmount() — Cleanup before component removal, similar to Vue's beforeDestroy

Modern Lifecycle Methods (React 16.3+)

Initialization Phase

  • constructor(props)
  • static getDerivedStateFromProps(props, state) — Returns state object or null, called before render
  • render()
  • componentDidMount()

Update Phase

  • static getDerivedStateFromProps(props, state)
  • shouldComponentUpdate(nextProps, nextState)
  • render()
  • getSnapshotBeforeUpdate(prevProps, prevState) — Capture values before DOM updates
  • componentDidUpdate(prevProps, prevState, snapshot)

Destruction Phase

  • componentWillUnmount()

Error Handling

  • static getDerivedStateFromError(error)
  • componentDidCatch(error, info)

State Management with setState()

import React, { Component } from 'react';
import axios from 'axios';

export default class ProductList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: []
    };
  }

  componentDidMount() {
    axios.get('/api/products').then(response => {
      this.setState({
        products: response.data.results
      });
    });
  }

  render() {
    const { products } = this.state;
    return (
      <div>
        {products.map(item => (
          <div key={item.id}>
            <h3>{item.name}</h3>
            <span>${item.price}</span>
          </div>
        ))}
      </div>
    );
  }
}

Environment-Based Webpack Configuration

Install the cross-env package:

npm install cross-env --save-dev

package.json scripts:

"scripts": {
  "start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js",
  "build": "cross-env NODE_ENV=production webpack --config webpack.config.js"
}

webpack.config.js plugins:

const isDev = process.env.NODE_ENV === 'development';

module.exports = {
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HtmlWebPackPlugin({
      template: './src/index.html'
    })
  ]
};

API Request Abstraction

utils/httpClient.js

import axios from 'axios';

const isDev = process.env.NODE_ENV === 'development';

const httpClient = axios.create({
  baseURL: isDev ? '/api' : 'http://production-server.com'
});

httpClient.interceptors.request.use(config => {
  config.headers['Authorization'] = localStorage.getItem('authToken');
  return config;
});

httpClient.interceptors.response.use(response => {
  return response.data;
});

export default httpClient;

utils/endpoints.js

import httpClient from './httpClient';

const fetchProducts = (page = 0, limit = 10) => {
  return httpClient.get('/products', {
    params: { page, limit }
  });
};

const fetchSlides = (type = 'home') => {
  return httpClient.get('/slides', {
    params: { category: type }
  });
};

export { fetchProducts, fetchSlides };

Component Composition

ParentComponent.jsx

import React, { Component } from 'react';
import { fetchSlides, fetchProducts } from './utils/endpoints';
import ProductGrid from './ProductGrid';

export default class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      slides: [],
      products: []
    };
  }

  componentDidMount() {
    fetchSlides().then(data => {
      this.setState({ slides: data.results });
    });
    fetchProducts().then(data => {
      this.setState({ products: data.results });
    });
  }

  render() {
    return (
      <div>
        <div className="carousel">
          {this.state.slides.map(item => (
            <img key={item.id} src={item.imageUrl} alt="" />
          ))}
        </div>
        <ProductGrid items={this.state.products} />
      </div>
    );
  }
}

ProductGrid.jsx

import React, { Component } from 'react';

export default class ProductGrid extends Component {
  render() {
    return (
      <div className="product-list">
        <div className="product-item">
          <img src="" alt="" style={{ width: '80px' }} />
          <h4>Sample Product</h4>
          <p>$299.99</p>
        </div>
      </div>
    );
  }
}

Passing Props from Parent to Child

Parent components pass data to children via custom attributes. Variables, booleans, and numbers require curly braces:

<ProductGrid items={this.state.products} />

Child components access props through this.props:

import React, { Component } from 'react';

export default class ProductGrid extends Component {
  render() {
    return (
      <div>
        {this.props.items.map(product => (
          <div key={product.id}>
            <img src={product.thumbnail} style={{ width: '80px' }} />
            <h4>{product.name}</h4>
            <p>${product.price}</p>
          </div>
        ))}
      </div>
    );
  }
}

Prop Type Validation

Install prop-types package:

npm install prop-types --save
import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class ProductGrid extends Component {
  render() {
    return (
      <div>
        {this.props.items.map(product => (
          <div key={product.id}>
            <img src={product.thumbnail} style={{ width: '80px' }} />
            <h4>{product.name}</h4>
            <p>${product.price}</p>
          </div>
        ))}
      </div>
    );
  }
}

ProductGrid.propTypes = {
  items: PropTypes.array
};

Available type validators: bool, array, func, number, object, string, symbol, node, element.

Passing Data from Child to Parent

Children communicate with parents by receiving callback functions as props.

ChildComponent.jsx

import React, { Component } from 'react';

export default class ChildComponent extends Component {
  render() {
    return (
      <div>
        <button onClick={() => this.props.onSend('Data from child')}>
          Send to Parent
        </button>
      </div>
    );
  }
}

ParentComponent.jsx

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

export default class ParentComponent extends Component {
  handleChildData(payload) {
    console.log('Received from child:', payload);
  }

  render() {
    return (
      <div>
        <ChildComponent onSend={this.handleChildData.bind(this)} />
      </div>
    );
  }
}

React Project Scaffolding Options

Option 1: Create React App (Recommended)

npx create-react-app my-project

Option 2: Manual Setup

npm install -g create-react-app
create-react-app my-project

Option 3: Dva Framework

npm install -g dva-cli
dva new my-project

Tags: React component lifecycle State Management Props Event Handlers

Posted on Fri, 19 Jun 2026 17:37:28 +0000 by xyzleft