Skip to content

Component Lifecycle ​

The Component Lifecycle system provides a class-based approach to building components with lifecycle methods similar to React class components.

Features ​

  • Class-based components
  • Lifecycle methods
  • State management
  • Props handling
  • Refs system
  • Automatic cleanup

API Reference ​

Component Class ​

javascript
class MyComponent extends ReactExpress.Component {
  constructor(element) {
    super(element);
    this.state = {
      // Initial state
    };
  }
}

Lifecycle Methods ​

componentDidMount() ​

Called after the component is mounted to the DOM.

componentDidUpdate(prevProps, prevState) ​

Called after the component updates.

componentWillUnmount() ​

Called before the component is removed.

shouldComponentUpdate(nextProps, nextState, prevState) ​

Controls whether the component should update.

render() ​

Returns the component's HTML content.

State Management ​

setState(updater[, callback]) ​

Updates component state.

javascript
this.setState({ count: 5 });
// or
this.setState(state => ({ count: state.count + 1 }));

Props System ​

Props are passed via data attributes:

html
<div data-component="counter" data-prop-initial="5">
</div>

Access in component:

javascript
console.log(this.props.initial); // "5"

Refs System ​

Create refs in template:

html
<button ref="myButton">Click me</button>

Access in component:

javascript
this.refs.myButton.addEventListener('click', this.handleClick);

Examples ​

Counter Component ​

html
<div data-component="counter" data-prop-initial="0">
  <span ref="display"></span>
  <button ref="increment">+</button>
</div>

<script>
class Counter extends ReactExpress.Component {
  constructor(element) {
    super(element);
    this.state = {
      count: parseInt(this.props.initial) || 0
    };
  }

  componentDidMount() {
    this.refs.increment.addEventListener('click', () => {
      this.setState(state => ({
        count: state.count + 1
      }));
    });
  }

  render() {
    return `
      <span ref="display">${this.state.count}</span>
      <button ref="increment">+</button>
    `;
  }
}
</script>

Todo List ​

html
<div data-component="todo-list" data-prop-title="My Todos">
  <ul ref="list"></ul>
  <input ref="input" type="text">
  <button ref="add">Add</button>
</div>

<script>
class TodoList extends ReactExpress.Component {
  constructor(element) {
    super(element);
    this.state = {
      todos: []
    };
  }

  componentDidMount() {
    this.refs.add.addEventListener('click', () => {
      const text = this.refs.input.value;
      if (text) {
        this.setState(state => ({
          todos: [...state.todos, text]
        }));
        this.refs.input.value = '';
      }
    });
  }

  render() {
    return `
      <h2>${this.props.title}</h2>
      <ul ref="list">
        ${this.state.todos.map(todo => `
          <li>${todo}</li>
        `).join('')}
      </ul>
      <input ref="input" type="text">
      <button ref="add">Add</button>
    `;
  }
}
</script>

Best Practices ​

  1. Component Structure

    • Keep components focused
    • Use proper lifecycle methods
    • Clean up event listeners
  2. State Management

    • Initialize state in constructor
    • Use setState for updates
    • Avoid direct state mutation
  3. Props Handling

    • Validate props when needed
    • Use default props
    • Document required props
  4. Performance

    • Implement shouldComponentUpdate
    • Clean up resources
    • Optimize render method

Common Patterns ​

Data Fetching ​

javascript
class UserProfile extends ReactExpress.Component {
  constructor(element) {
    super(element);
    this.state = {
      user: null,
      loading: true,
      error: null
    };
  }

  async componentDidMount() {
    try {
      const response = await fetch('/api/user');
      const user = await response.json();
      this.setState({ user, loading: false });
    } catch (error) {
      this.setState({ error, loading: false });
    }
  }

  render() {
    if (this.state.loading) return '<div>Loading...</div>';
    if (this.state.error) return '<div>Error loading user</div>';
    
    const { user } = this.state;
    return `
      <div>
        <h2>${user.name}</h2>
        <p>${user.email}</p>
      </div>
    `;
  }
}

Form Handling ​

javascript
class ContactForm extends ReactExpress.Component {
  constructor(element) {
    super(element);
    this.state = {
      name: '',
      email: '',
      message: ''
    };
  }

  componentDidMount() {
    this.refs.form.addEventListener('submit', (e) => {
      e.preventDefault();
      // Handle submission
    });
  }

  render() {
    return `
      <form ref="form">
        <input ref="name" value="${this.state.name}">
        <input ref="email" value="${this.state.email}">
        <textarea ref="message">${this.state.message}</textarea>
        <button type="submit">Send</button>
      </form>
    `;
  }
}
javascript
class Modal extends ReactExpress.Component {
  constructor(element) {
    super(element);
    this.state = {
      isOpen: false
    };
  }

  componentDidMount() {
    this.refs.overlay.addEventListener('click', (e) => {
      if (e.target === this.refs.overlay) {
        this.setState({ isOpen: false });
      }
    });
  }

  render() {
    return `
      <div ref="overlay" class="modal-overlay ${this.state.isOpen ? 'open' : ''}">
        <div class="modal-content">
          ${this.props.content}
          <button ref="close">Close</button>
        </div>
      </div>
    `;
  }
}