Actions

Actions expose a component's public methods. They're like buttons on your component that other components or code can trigger. Just as a TV remote has buttons for changing channels or volume, your component can have actions for functionality like "increment", "reset", and "submit".

Written By Joel

Last updated About 1 month ago


Declaring Actions

Actions are declared in the components options:

defineComponent("counter", {
  store: {
    count: 0
  },
  actions: {
    reset(ctx) {
      ctx.store.count = 0;
    },
    increment(ctx) {
      ctx.store.count++;
    },
  }
});

Action Context

Each action receives a context object that provides access to the component's state and functionality:


defineComponent('rq-counter', {
  props: {
    max: 10,
  },
  store: {
    count: 0,
  },
  actions: {
    // Action with no arguments
    increment(ctx) {
      ctx.actions.add(1);
    },
    // Action with arguments
    add(ctx, amount) {
      const max = ctx.props.max
      const newCount = ctx.store.count + amount;
      if (newCount <= max) {
        ctx.store.count = newCount;
      }
    },
  },
  setup(component, props, store, actions) {
    // Bind count value
    component.query('count').text(() => store.count);

    // Call increment action
    component.query('button').on('click', (evt) => {
      actions.increment();
    });
  },
});

Properties

props

Access the component's props:

add(ctx, amount) {
  const max = ctx.props.max
  ...
},

store

Access and modify the component's state:

add(ctx) {
  const max = ctx.props.max
  const newCount = ctx.store.count + amount;
  if (newCount <= max) {
    ctx.store.count = newCount;
  }
},

actions

Call other actions from within an action:

increment(ctx) {
  ctx.actions.add(1)
},

Using Actions

There are several ways to access a component's actions:

From Setup Function

Access your own component's actions:

HTML

<rq-counter>
  <button rq="increment">+</button>
  <span rq="count">0</span>
</rq-counter>

JavaScript

defineComponent("rq-counter", {
  store: {
    count: 0
  },
  actions: {
    increment(ctx) {
      ctx.store.count++;
    }
  },
  setup(component, props, store, actions) {
    // Display count
    component.query("count").text(() => store.count);

    // Handle internal button
    component.query("increment").on("click", (evt) => {
      actions.increment();
    });
  }
});

From Parent Component

Access a child components actions:

HTML

<rq-parent prop:key="parent">
  <rq-counter prop:key="counter1">
    <button rq="increment">Internal +</button>
    <span rq="count">0</span>
  </rq-counter>
  <button rq="button">External +</button>
</rq-parent>

JavaScript

defineComponent("rq-parent", {
  setup(component, props, store) {
    component.query('button').on('click', (evt) => {
      const counter = component.components.get('counter1');
      counter?.actions.increment();
    });
  }
});

Via Query Component

Access any component's actions globally:

// Get component instance
const counter = queryComponent("rq-counter", "counter1");
    
// Call its increment action
counter?.actions.increment();

Typescript

You can type your actions for better TypeScript support:

interface Props {
  max: number;
}

interface Store {
  count: number;
}

interface Actions extends RqActions<Props, Store> {
  increment: (ctx: RqActionContext<Props, Store>) => void;
  add: (ctx: RqActionContext<Props, Store>, amount: number) => void;
}

defineComponent('rq-parent', {
  setup(component, _props, _store) {
    // Call counter's actions
    component.query('button').on('click', (evt) => {
      const counter = component.components.get('counter1');
      counter?.actions.increment();
    });
  },
});

defineComponent<Props, Store, Actions>('rq-counter', {
  props: {
    max: 10,
  },
  store: {
    count: 0,
  },
  actions: {
    // Action with no arguments
    reset(ctx) {
      ctx.store.count = 0;
    },
    // Action with arguments
    add(ctx, amount) {
      const newCount = ctx.store.count + amount;
      if (newCount <= ctx.props.max) {
        ctx.store.count = newCount;
      }
    },
    // Action referencing actions
    increment(ctx) {
      ctx.actions.add(1);
    },
  },
  setup(component, _props, store, actions) {
    // Bind count value
    component.query('count').text(() => store.count);

    // Call action with no arguments
    component.query('increment').on('click', (evt) => {
      actions.increment();
    });

    // Call action with arguments
    component.query('increment2').on('click', (evt) => {
      actions.add(2);
    });
  },
});

Could not load article.

Could not load article.