model

information

By default, the export package name for all APIs in this section is: @modern-js/runtime/model.

If Reduck is integrated separately from Modern.js, the export package name is: @modern-js-reduck/react.

TIP

The original type of Reduck is complex. The following type definition shows the simplified type information. For the original type, see model.

model

Create a Model for managing application state.

function model(name: string): { define: function }

  • name: string, the unique id of the Model created.
example
model('foo');

define

Used to define the detailed structure of the Model, supporting passing in an object type or function type parameter.

Object Type

function define(modelDesc: ModelDesc): Model;

  • modelDesc: ModelDesc, definition of Model structure, includes statecomputedactionseffects etc. props.
example
const fooModel = model('foo').define({
  state: 'foo',
  computed: {
    cFoo: state => `c${state}`,
  },
  actions: {
    setState: (state, value) => {
      return value;
    },
  },
  effects: {
    loadState: async () => {
      // get state from remote
    },
  },
});

Function Type

function define((context: Context, utils: Utils) => ModelDesc): Model;

  • context: Reduck Context, can get underlying store object. store support all Redux Store API, also mounts the use method for consuming the Model, and the unmount method for unmounting the Model.
  • utils: commonly used tool like useonMount. use is the same as store.use, onMount is the hook function after the Model is mounted.
interface Utils {
  use: UseModel;
  onMount: OnMountHook;
}

interface Context {
  store: ReduxStore & {
    use: UseModel;
    unmount: (model: Model) => void;
  };
}

For example, through use, you can get the state and actions of the Model itself and other Models.

example
const fooModel = model('foo').define(() => {
  return {
    state: 'foo',
    actions: {
      setState: (state, value) => {
        return value;
      },
    },
  };
});

const barModel = model('bar').define((_, { use }) => {
  return {
    state: 'bar',
    effects: {
      syncFoo() {
        const [state, actions] = use(fooModel);
        actions.setState(state);
      },
    },
  };
});

Input

ModelDesc.state

Define the state of the Model. Technically, any type of State is supported, but in practice it is recommended to use a JSON serializable type.

interface ModelDesc {
  state: any;
}

ModelDesc.actions

Define the Actions of the Model. The function type of Actions is:

interface ModelDesc {
  actions: {
    [actionKey: string]: (state: State, payload: any) => State | void;
  };
}

Reduck internally integrates immer, which can directly return the original state. When the Action has no explicit return value, Reduck internally returns a modified new State object.

ModelDesc.computed

Defines the derived state of the Model. The definition of derived state supports two types:

  1. Depends only on the state of the Model itself
interface ModelDesc {
  computed: {
    [computedKey: string]: (state: State) => any;
  };
}
  1. Depends on the state of other Models
interface ModelDesc {
  computed: {
    [computedKey: string]: [
      ...models: Model[],
      (state: State, ...args: ModelState[]) => any,
    ];
  };
}
example
const fooModel = model('foo').define({
  state: 'foo',
});

const barModel = model('bar').define({
  state: 'bar',
  computed: {
    combineFoo: [fooModel, (state, fooState) => state + fooState],
  },
});

ModelDesc.effects

Defines the Effects of the Model. The function types defined in Effects are:

interface ModelDesc {
  effects: {
    [effectKey: string]: (...args: any[]) => any;
  };
}
example
const fooModel = model('foo').define((context, { use }) => ({
  state: 'foo',
  effects: {
    persist() {
      const [state] = use(fooModel);
      localStorage.setItem('state', state);
    },
  },
}));