The behaviour of hooks is heavily inspired by WordPress Hooks.
It is highly recommended to get familiar with how WordPress hooks work first
There are three types of hooks
The key differences from WordPress are:
context
object. In the frontend is empty, in the backend it has the req
property which contains the request objectreturn_value
received from the last moduleYou can use hooks and filters from anywhere in the code as the functions are globally provided:
Actions allow you to execute functionality and return a value from them
Frontend:
frontendConnector({ hooks: { actions: [{ // return_value is the result returned by the previous executed hook // arg1, arg2, ...args are the argument passed when triggering the hook hook_action_name: (context, return_value, arg1, arg2, ...args) => { return return_value; } }] } }); // use_frontend_action is globally available, no need to import it const value_from_action = use_frontend_action.hook_action_name(1, 2, 3); console.log('value: ' + value_from_action);
Backend:
import express from 'express'; import { onRequestHook_Express } from '@stlse/backend-connector'; const app = express(); backendConnector({ onRequest: onRequestHook_Express(app), hooks: { actions: [{ // return_value is the result returned by the previous executed hook // arg1, arg2, ...args are the argument passed when triggering the hook different_name_actions: (context, return_value, arg1, arg2, ...args) => { console.log(context.req) // has the req object return return_value; } }] } }) app.get('/', async (req, res, next) => { try { // all hooks are async in backend, so we must await // use_frontend_action is globally available, no need to import it const value_from_action = await use_frontend_action.different_name_actions(req, 1, 2, 3); res.send({value: value_from_action}) } catch (e) { next(e); } })
Filters allow you to expose a value to modify and then return a different value
Frontend:
frontendConnector({ hooks: { filters: [{ // return_value is the result returned by the previous executed hook // arg1, arg2, ...args are the argument passed when triggering the hook hook_filter_name: (context, return_value, arg1, arg2, ...args) => { return return_value; } }] } }); // use_frontend_filter is globally available, no need to import it const filtered_value = use_frontend_filter.hook_filter_name(1, 2, 3); console.log('value: ' + filtered_value);
Backend:
import express from 'express'; import { onRequestHook_Express } from '@stlse/backend-connector'; const app = express(); backendConnector({ onRequest: onRequestHook_Express(app), hooks: { filters: [{ // return_value is the result returned by the previous executed hook // arg1, arg2, ...args are the argument passed when triggering the hook different_name_filters: (context, return_value, arg1, arg2, ...args) => { console.log(context.req) // has the req object return return_value; } }] } }) app.get('/', async (req, res, next) => { try { // all hooks are async in backend, so we must await // use_backend_filter is globally available, no need to import it const filtered_value = await use_backend_filter.different_name_filters(req, 1, 2, 3); res.send({value: filtered_value}) } catch (e) { next(e); } })
React Hooks are similar to filters, you can specify where a hook should be and other modules can inject their own component into the hook. They work as normal react component and you can pass props.
They even work with different React versions!
Frontend only:
frontendConnector({ hooks: { react: [{ // otherComponents is an Array of all the components returned by previous hooks name_of_hook: (context, otherComponents) => MyComponent, }] } }); function MyComponent(props) { return ( <div> Hello, here is the number from the props: {props.number} </div> ) } function Template() { return ( <div> Below here will appear all react components that have been injected into "name_of_hook" <React_use_hook ruhName="name_of_hook" number={10}/> </div> ) }
A note on compatibility with different react versions:
If you are using two modules with different react version, then the react hooks automatically ensure that the two different version can cooperate,
but if you want to pass a React component in filter hook or in an action hook, you have to manually wrap them by using the utilities returned from getReactWrapper()
Example:
import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { createPortal } from 'react-dom'; import { frontendConnector, getReactWrapper } from '@stlse/frontend-connector'; // getReactWrapper returns you two different wrappers which can be used in two different methods listed below const { ReactWrap, wrapComponent } = getReactWrapper({ React, ReactDOM, createPortal }); frontendConnector({ hooks: { filter: [{ filter_that_has_a_list_of_react_components: (context, return_value) => { // method 1 const wrapped = <ReactWrap><MyComponent/></ReactWrap>; return_value.push(wrapped); // method 2 const HigherOrderComponentWrap = wrapComponent(Alternative); return_value.push(<HigherOrderComponentWrap/>) return return_value; }, }] } }); function MyComponent() { const [n, sn] = React.useState(0); return ( <div> Hello, here is the alternative 1 <button onClick={() => sn(n + 1)}>test: {n}</button> </div> ) } function Alternative() { const [n, sn] = React.useState(0); return ( <div> Hello, here is the alternative 2 <button onClick={() => sn(n + 1)}>test: {n}</button> </div> ) } function Template() { // use_frontend_filter is globally available, no need to import it const listOfComponents = use_frontend_filter.filter_that_has_a_list_of_react_components([]); return ( <div> Below here will appear all react components that have been injected into "filter_that_has_a_list_of_react_components" {listOfComponents} </div> ) }