State

State represents data that can change over time. Unlike props, state is managed by the component itself and can be updated.

Initializing State

Initialize state in the constructor:

from pyreact import element, Component

class Counter(Component):
    def __init__(self, props):
        super().__init__(props)
        self.state = {'count': 0}

Updating State

Use setState() to update state:

class Counter(Component):
    def __init__(self, props):
        super().__init__(props)
        self.state = {'count': 0}

    def increment(self, event):
        # ✅ Correct: Use setState
        self.setState({'count': self.state['count'] + 1})

    def bad_increment(self, event):
        # ❌ Wrong: Never modify state directly
        self.state['count'] += 1  # Don't do this!

State Updates are Merged

setState() merges the new state with the existing state:

class Form(Component):
    def __init__(self, props):
        super().__init__(props)
        self.state = {
            'name': '',
            'email': '',
            'age': 0
        }

    def update_name(self, event):
        # Only updates 'name', preserves 'email' and 'age'
        self.setState({'name': event.target.value})

    def update_email(self, event):
        self.setState({'email': event.target.value})

Functional Updates

When new state depends on previous state, use a function:

class Counter(Component):
    def __init__(self, props):
        super().__init__(props)
        self.state = {'count': 0}

    def increment(self, event):
        # Use function for derived state
        self.setState(lambda state: {'count': state['count'] + 1})

    def increment_three_times(self, event):
        # Multiple updates
        self.setState(lambda state: {'count': state['count'] + 1})
        self.setState(lambda state: {'count': state['count'] + 1})
        self.setState(lambda state: {'count': state['count'] + 1})

State is Local

State is local to the component:

class App(Component):
    def render(self):
        return element('div', {},
            element(Counter, {}),  # Has its own state
            element(Counter, {}),  # Has its own state
            element(Counter, {})   # Has its own state
        )

Lifting State Up

Share state between components by lifting it to their common ancestor:

class App(Component):
    def __init__(self, props):
        super().__init__(props)
        self.state = {'temperature': 0}

    def handle_change(self, temp):
        self.setState({'temperature': temp})

    def render(self):
        return element('div', {},
            element(TemperatureInput, {
                'temperature': self.state['temperature'],
                'onChange': self.handle_change
            }),
            element(BoilingVerdict, {
                'celsius': self.state['temperature']
            })
        )

State vs Props

Props

State

Passed from parent

Managed by component

Read-only

Can be updated

Used for configuration

Used for dynamic data

External to component

Internal to component

Best Practices

  1. Minimize state - Keep state as simple as possible

  2. Lift state up - Share state by lifting to common ancestor

  3. Don’t duplicate state - Compute derived values instead

  4. Use setState - Never modify state directly

Next Steps