Chonky v2.1.0 Docs
IntroductionInstallation & usageFile Browser demosMigrating from 1.xFAQ
Basics

Understanding effects

It is finally time to dive deep into Chonky's most powerful feature - file action effects. "Effect" in this context means a "side effect" of the action. It has nothing to do with React's useEffect.

Please note that action effects are an advanced feature. As such, using them effectively requires a fair bit of Redux knowledge and understanding Chonky's internal logic.

Why are effects useful?

On the Defining custom actions page, you saw how you could change some basic parts of Chonky's internal state, e.g. the current sorting function or the file selection. While the mechanisms presented on that page are useful, they only cover roughly 10% of Chonky's internal Redux state.

There's no doubt advanced users will want to read or set other parts of Chonky's Redux state. At the same time, it is clearly impractical to provide explicit mechanisms to alter every part of the state, because it will result in a highly fragile API that will be hard to maintain.

Enter action effects. They provide a generic mechanism for accessing and modifying Chonky's state by directly exposing its Redux state and Redux dispatch to developers. This creates many interesting opportunities, like completely changing the meaning of single & double clicks or chaining file actions. Unsurprisingly, many Chonky's built-in actions use effects to make things happen.

There is an obvious downside to this approach - to make full use of action effects, one should have a good understanding of what is stored in Chonky's Redux state, and what Redux actions and thunks are available. While I agree that this is inconvenient, I also think it is much better than the alternative, which is to fork Chonky on GitHub and rewrite parts of code yourself.

Action effect definition

Recall the defineFileAction helper method from the Defining custom actions page:

defineFileAction(action: FileAction, effect?: FileActionEffect) => FileAction;

The second parameter is what you use to define the effect. Formally, effects should follow the FileActionEffect type:

export type FileActionEffect<Action extends FileAction = any> = (data: {
action: Action;
payload: Action['__payloadType'];
state: FileActionState<{}>; // extra state is empty on purpose
reduxDispatch: ChonkyDispatch;
getReduxState: () => RootState;
}) => MaybePromise<undefined | boolean | void>;

You should already know about action, payload and state parameters from the Defining an action handler page.

The new parameters are reduxDispatch and getReduxState. If you ever used Redux with redux-thunk middleware, you know exactly what they do - reduxDispatch lets you dispatch Redux actions or thunks to Chonky's Redux store, and getReduxState lets you get Chonky's internal Redux state.

Effect return value

Note that the effect function is executed as the last step in Chonky's action processing pipeline, right before dispatching the action to the user-defined action handler. If you want to prevent the action handler from being called, you can return true from your effect. Alternatively, you can return a promise that resolves into true.

Example action effect

Consider the definition of Chonky's built-in OpenParentFolder action:

import {
ChonkyActions,
ChonkyIconName,
defineFileAction,
FileHelper,
thunkRequestFileAction,
} from 'chonky';
import { selectParentFolder } from 'chonky/lib/redux/selectors';
const OpenParentFolder = defineFileAction(
{
id: 'open_parent_folder',
hotkeys: ['backspace'],
button: {
name: 'Go up a directory',
toolbar: true,
contextMenu: false,
icon: ChonkyIconName.openParentFolder,
iconOnly: true,
},
} as const,
({ reduxDispatch, getReduxState }) => {
const parentFolder = selectParentFolder(getReduxState());
if (FileHelper.isOpenable(parentFolder)) {
reduxDispatch(
thunkRequestFileAction(ChonkyActions.OpenFiles, {
targetFile: parentFolder,
files: [parentFolder],
})
);
}
}
);

This action definition demonstrates two important concepts:

  1. It shows that you can use any of Chonky's built-in Redux selectors by importing them from chonky/lib/redux/selectors. You can see the full list in selectors.ts on GitHub. You can also define your own selectors if you want.
  2. It shows that you can use the thunkRequestFileAction thunk to trigger actions from Chonky. The simplified method signature for this thunk looks like this:
    thunkRequestFileAction(
    action: FileAction,
    payload: FileAction['__payloadType']
    ) => MaybePromise<void>;
    Note that payload is a required parameter. For actions that don't have a payload, you can just pass undefined.

Available resources for action effects

File action effects rely heavily on Redux actions and selectors, so it's very useful to understand how they work. There are many Redux resources available on Google, but you can start with Redux Overview from the official Redux docs.

It is also useful to know what Redux actions, selectors and thunks Chonky actually defines:

  • Chonky's Redux state:

    • redux.types.ts: This file shows the Typescript interface for Chonky's Redux state.
    • state.ts: This file shows the initial state for Chonky's Redux store. Note that most of initial state is overwritten when FileBrowser component mounts, so don't rely on the contents of this file too much.
  • Redux selectors:

    • selectors.ts: This file shows all of the built-in Redux selectors. Of course you are free to define your own selectors, or just access the state object directly.

    • Example usage:

      import { selectCleanFileIds } from 'chonky/lib/redux/selectors';
      defineFileAction(
      { id: 'selector_example_action' } as const,
      ({ getReduxState }) => {
      const cleanFileIds = selectCleanFileIds(getReduxState());
      console.log('Non-null file IDs:', cleanFileIds);
      }
      );
  • Redux thunks:

    • files.thunks.ts: This file contains thunks related to different file operations - setting the new file array, sorting files, setting the current search string, etc.

    • file-actions.thunks.ts: This file contains thunks related to common file action operations - setting the current file view, applying a selection transform, toggling options, etc.

    • dispatchers.thunks.ts: This file contains thunks related to requesting and dispatching file actions.

    • Example usage:

      import { thunkUpdateSearchString } from 'chonky/lib/redux/thunks/files.thunks';
      defineFileAction(
      { id: 'thunks_example_action' } as const,
      ({ reduxDispatch }) => {
      // Set search to all Photoshop files (.psd)
      reduxDispatch(thunkUpdateSearchString('.psd'));
      }
      );
  • Redux actions:

    • reducers.ts - This file exports the reduxActions constant, which holds all of Chonky's Redux actions. You can see that reducers object defines a bunch of functions - you can call any of them as an action. You can read more about createSlice method from Redux Toolkit to understand what is happening under the hood.

    • Example usage:

      import { reduxActions } from 'chonky/lib/redux/reducers';
      defineFileAction(
      { id: 'redux_actions_example_action' } as const,
      ({ reduxDispatch }) => {
      // Disable selection
      reduxDispatch(reduxActions.setSelectionDisabled(true));
      }
      );

It is also useful for you to review the definitions of Chonky's essential built-in actions on GitHub. They define many different effects, and they are a good example of what action effects can do.

Questions and suggestions

If you have a question about action effects, or want to request an addition to Chonky's Redux state or Redux actions, you can create an issue on GitHub or join Chonky's Discord server.

Defining your own action effect

As you might know, you can use the disableSelection prop on FileBrowser to toggle the file selection feature on and off. We will define a custom action that will allow your users to toggle selection functionality from the UI (using file effects).

Try selecting some file in the file browser below then clicking on Disable selection button.

0 items

If you have a question, want to request a feature or report a bug, please create an issue on GitHub. You can also report inaccurate or unclear documentation on Chonky's Discord server.