Git Product home page Git Product logo

flux-standard-action's Introduction

Flux Standard Action

Build Status codecov npm Version npm Downloads Monthly

Introduction

A human-friendly standard for Flux action objects. Feedback welcome.

Motivation

It's much easier to work with Flux actions if we can make certain assumptions about their shape. For example, essentially all Flux actions have an identifier field, such as type, actionType, or actionId. Many Flux implementations also include a way for actions to indicate success or failure, especially as the result of a data-fetching operation. Defining a minimal, common standard for these patterns enables the creation of useful tools and abstractions.

Errors as a first class concept

Flux actions can be thought of as an asynchronous sequence of values. It is important for asynchronous sequences to deal with errors. Currently, many Flux implementations don't do this, and instead define separate action types like LOAD_SUCCESS and LOAD_FAILURE. This is less than ideal, because it overloads two separate concerns: disambiguating actions of a certain type from the "global" action sequence, and indicating whether or not an action represents an error. FSA treats errors as a first class concept.

Design goals

  • Human-friendly. FSA actions should be easy to read and write by humans.
  • Useful. FSA actions should enable the creation of useful tools and abstractions.
  • Simple. FSA should be simple, straightforward, and flexible in its design.

Example

A basic Flux Standard Action:

{
  type: 'ADD_TODO',
  payload: {
    text: 'Do something.'  
  }
}

An FSA that represents an error, analogous to a rejected Promise:

{
  type: 'ADD_TODO',
  payload: new Error(),
  error: true
}

Actions

An action MUST

  • be a plain JavaScript object.
  • have a type property.

An action MAY

  • have an error property.
  • have a payload property.
  • have a meta property.

An action MUST NOT include properties other than type, payload, error, and meta.

type

The type of an action identifies to the consumer the nature of the action that has occurred. type is a string constant. If two types are the same, they MUST be strictly equivalent (using ===).

payload

The optional payload property MAY be any type of value. It represents the payload of the action. Any information about the action that is not the type or status of the action should be part of the payload field.

By convention, if error is true, the payload SHOULD be an error object. This is akin to rejecting a promise with an error object.

error

The optional error property MAY be set to true if the action represents an error.

An action whose error is true is analogous to a rejected Promise. By convention, the payload SHOULD be an error object.

If error has any other value besides true, including undefined and null, the action MUST NOT be interpreted as an error.

meta

The optional meta property MAY be any type of value. It is intended for any extra information that is not part of the payload.

Utility functions

The module flux-standard-action is available on npm. It exports a few utility functions.

isFSA(action)

import { isFSA } from 'flux-standard-action';

Returns true if action is FSA compliant.

isError(action)

import { isError } from 'flux-standard-action';

Returns true if action represents an error.

Libraries

  • redux-actions - a set of helpers for creating and handling FSA actions in Redux.
  • redux-promise - Redux promise middleware that supports FSA actions.
  • redux-rx - RxJS utilities for Redux, including a middleware that supports FSA actions.

flux-standard-action's People

Contributors

3af avatar acdlite avatar arelav avatar cappslock avatar christopherstyles avatar fredrikhr avatar greenkeeper[bot] avatar harukaeru avatar jakxz avatar loklaan avatar pspsynedra avatar pwnn avatar smrq avatar timche avatar tomchentw avatar unional avatar vadimkorobka avatar wub avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flux-standard-action's Issues

Serializable?

Should FSA mandate actions to be serializable? I think it's a good requirement (prevents people from passing callbacks inside actions). It's also great for the tooling, as it's easy to build Flux over websockets, or a persistent debug session solution, without worrying that something might get lost.

I propose the following changes:

  • invariant(isDeepEqual(action, JSON.parse(JSON.stringify(action))))
  • Therefore, type must be a String, not a Symbol

We could then write a middleware that checks actions for compliance in development.

Replace status with boolean error field

There's been a lot of confusion about status and its purpose. You can read some of the reasoning behind it here: #4 (comment)

I propose we replace status with a boolean error field. If error is true, then the action represents an error, and the payload should (by convention, like with rejected promises) be an error.

Action creator example

Is it safe to assume that action creators should always have the following signature?

export function someAction(payload, error, meta) {
    return {
        type: SOME_ACTION,
        payload,
        error,
        meta
    };
};

Error at the Action?

I'm coming to flux from a Rails/Ruby world (gasp!)

As I'm wrapping my head around Flux and standards (like FSA) I'm finding some questions pop up in my head, and whom better to answer than the FSA community/creator.

In FSA why is error state the job of the Action? That seems like we've overstepped, and for the wrong reasons. I don't think it's the action's job to choose something like validity (validity is a state).

An action is an abstract description of an operation to be performed. In databases you have transactions, in Android you have Intents, and in Rails you can attempt to modify a Model, but there's no guarantee that it will succeed, or yield a change. Should that be an error state? I think the reducer knows best.

Think of this:
I can't buy -1 of something, but who's job should it be to tell me that? When I press the minus button on a cart, should my action check state to see if I'm at zero, and violate separation of concerns? Or should it just fire the action and my reducers take care of state (one managing my cart number at zero and another showing a red exclamation mark animation). Ok, not a great example, but I think it expresses the point. I feel errors shouldn't be part of actions, and I'm interested in hearing why otherwise.

EDIT

TL:DR; The error flag in FSA is bad

An in-range update of mocha is breaking the build 🚨

Version 3.4.0 of mocha just got published.

Branch Build failing 🚨
Dependency mocha
Current Version 3.3.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As mocha is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ

Status Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Release Notes v3.4.0

Mocha is now moving to a quicker release schedule: when non-breaking changes are merged, a release should happen that week.

This week's highlights:

  • allowUncaught added to commandline as --allow-uncaught (and bugfixed)
  • warning-related Node flags

πŸŽ‰ Enhancements

πŸ› Fixes

πŸ”© Other

Commits

The new version differs by 9 commits0.

  • 7554b31 Add Changelog for v3.4.0
  • 9f7f7ed Add --trace-warnings flag
  • 92561c8 Add --no-warnings flag
  • ceee976 lint test/integration/fixtures/simple-reporter.js
  • dcfc094 Revert "use semistandard directly"
  • 93392dd no special case for macOS running Karma locally
  • 4d1d91d --allow-uncaught cli option
  • fb1e083 fix allowUncaught in browser
  • 4ed3fc5 Add license report and scan status

false

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Should we add a meta field?

{
  type,
  status,
  payload: {...}
  meta: {...}
}

This would keep the top-level action object predictable β€” 1 required property (type), and 3 optional properties. All other properties at the top-level would be invalid.

@goatslacker @taion

Consider renaming `body` to `payload`?

By request from #redux on reactiflux...

Admittedly this is pedantic, would you consider renaming body to payload? I thought the term payload was used in Facebook's original Flux guides, but I didn't see it. So perhaps other implementations use payload? I know that you had commented that Flummox uses body. It probably doesn't matter much, but body makes me think that I'm dealing with a web response.

What is the reason error property is boolean?

as opposed to an instance of Error object. Boolean flag is vague. It just says what the error is and does not standardise the method of getting error description. Docs say that payload by convention should be an Error object.

Migrate types to DefinitelyTyped

I wrote some types signatures for the redux-duck library. It creates FSA actions so I used the types from flux-standard-action for those. Then I opened a pull request against DefinitelyTyped that is the de facto place for storing javascript library type signatures. However, it turns out that linking to types that are not part of the DefinitelyTyped repository is problematic. It seems they only do it for substantial libraries written in TypeScript. I'm now wondering if you are perhaps interested in migrating your index.d.ts to DefinitelyTyped to make it's reuse easier.

Typings make meta a required property

Using TypeScript and the included typings makes meta a required property in a FSA.

import {FluxStandardAction as Action} from 'flux-standard-action'
public static updateYear(year: string): Action<string, null>
{
    return {
        type: Actions.SDS_VEHICLE_SELECTION_YEAR_UPDATE,
        payload: year
    }
}

This will complain that meta does not exist in my action. Looking at the typings, I see that meta is no longer optional:

export interface FluxStandardAction<Payload, Meta> {
  /** ... **/
  meta: Meta;  // Notice the lack of ?
}

Is this wanted behavior?

Description of type

Why is type defined like

The type of an action identifies to the consumer the nature of the action that has occurred. Two actions with the same type MUST be strictly equivalent (using ===). By convention, type is usually string constant or a Symbol.

Two actions with the same type MUST be strictly equivalent. But if they have different payloads, this is not true anymore.

This doesn't make sense to me.

when to update to babel6 ?

I use the redux-actions && redux-promise and React-Native 0.17 ,but the RN17 use babel 6,and and redux-actions && redux-promise dependency flux-standard-action which use babel 5
so ,My Project can not be builded success, so that I have to change the React Native to 14
So,Could you update to the Babel 6?

What is the reason action name is called "type"?

What is the origin of a convention to call action name (e.g. ADD_NAME, REMOVE_NAME) a "type" (or "actionType" or "actionId")?

"actionId" is the most accurate of the suggested variations. However, what we are calling a "type" is actually a "name".

It is easy to see that "type" is wrong if you either lookup dictionary definition or try to replace it with either of the direct synonyms (e.g. kind, sort, variety).

Suggestion - Provide class/factory function as default export

Hi there, have you ever considered providing a basic class/factory function as the default export for the package? It'd provide some syntactic sugar when writing your actions. I imagine the usage would be kinda like this:

import Action from 'flux-standard-action'

export function setUsername(username) {
  return new Action('SET_USERNAME', username);
}

If you're open to it, I can make the PR. Thanks!

An in-range update of conventional-github-releaser is breaking the build 🚨

Version 1.1.8 of conventional-github-releaser just got published.

Branch Build failing 🚨
Dependency conventional-github-releaser
Current Version 1.1.7
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As conventional-github-releaser is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ

Status Details
  • ❌ coverage/coveralls Coverage pending from Coveralls.io Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Why SHOULD payload be an error object? error: true should be enough

I think this is quite limiting.

You say this β€”

  • An action whose error is true is analogous to a rejected Promise

Isn't that enough? What if I deal with a server that sends helpful error code and messages in case of failure? For example a 401 response may include something like this:

{
  "code": "WRONG_PASSWORD",
  "message": "Password field should not be empty"
}

So I naturally dispatch this object as payload and set { error: true }.

I guess what you're implying is that I should put this error object inside the meta property. This seems contradictory to me. This is object is obviously payload.


Another thing that bothers me is that I can't find a payload of type Error useful for anything. It can only hold a string, so it's pretty useless to keep in state, isn't it? (not to say that strings are useless, but you can see that we could pass much more information about the error)

Get state in action creator

With the thunk middleware, you get getState as the second argument.

Do you have any suggestion on how I could use the current store state in my promise?
Currently I need this to get auth tokens for my API.

Question/Clarification re: "Two actions with the same type MUST be strictly equivalent"

As defined in the readme, I think a strict reading says that two actions of the same type must be strictly equivalent, i.e.:

firstActionOfTypeA === secondActionOfTypeA

But my interpretation is that the intent is to say that the type values must be strictly equivalent, not the two actions themselves, i.e.:

firstActionOfTypeA.type === secondActionOfTypeA.type
firstActionOfTypeA !== secondActionOfTypeA

If i'm both reading and interpreting correctly, I think the section might need rewording. So my question is, am I doing both of those things correctly? πŸ˜›

An in-range update of cross-env is breaking the build 🚨

Version 3.2.0 of cross-env just got published.

Branch Build failing 🚨
Dependency cross-env
Current Version 3.1.4
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As cross-env is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ


Status Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details
Release Notes v3.2.0

<a name"3.2.0">

3.2.0 (2017-03-04)

Features

  • revamp: revamp the entire lib (backward compatible) (#63) (dad00c46)
Commits

The new version differs by 4 commits .

  • dad00c4 feat(revamp): revamp the entire lib (backward compatible) (#63)
  • e33a85c docs(README): Add doc for cross-var. (#58)
  • 5e590ec docs(README): added how to use cross-env to run npm sub-scripts (#53)
  • afdb2de docs(README): mention BashΒ onΒ Windows (#49)

See the full diff.

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Examples for "meta"

Right now it is a bit diffuse when one should use meta over payload. Some more descriptive examples might be a good idea?

Proposal

Continuing from our conversation on slack:

{
  // string | number: a unique identifier for the dispatch
  id: 'abcdef123',

  // any: Symbol, string, number, object, function. A unique way to identify the action dispatched
  type: ActionTypes.ADD_TODO,

  // any: whatever is being dispatched
  payload: { text: 'Create FSA Proposal' },

  // information about the action itself
  action: {
    // string representation of the particular action type
    // since Symbols are not strings and action type can be anything, having a way to identify an
    // action as a string is useful for serializing, debugging, and logging.
    id: 'ActionTypes.ADD_TODO'
  },

  // other information about the dispatch
  meta: {
    // no opinions here...
    status: 'success'
  }
}

There's a difference between dispatch and action. I need to uniquely identify dispatches, this is useful for time travel, rollback, etc. I also need to be able to unique identify actions, this is good for logging and debugging.

I think this is a good MVP. I was using details for action information in alt but I think action is a better name.

An in-range update of eslint-config-airbnb-base is breaking the build 🚨

Version 11.1.0 of eslint-config-airbnb-base just got published.

Branch Build failing 🚨
Dependency eslint-config-airbnb-base
Current Version 11.0.1
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As eslint-config-airbnb-base is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ


Status Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details
Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Why must an action "NOT include properties other than type, payload, and error, and meta"?

I for example have built a history management package that changes URLs based on action types and a routing config map. Using middleware, I add location and prevLocation keys to payloads, but I rather pass them as keys on the action, so that the payload would be what it was before adding my middleware. So would it really be a crime for a package to add additional keys?

ps. I could add my keys to meta, but I feel like too many other packages are possibly hijacking that, and could break what I've put on the meta key. That basically summarizes the benefits of allowing for additional keys--package authors can essentially namespace their "meta" data and therefore do a better job of preventing it from being fooled with. Perhaps it's just best application developers stick to these conventions so that they can take advantage of the larger number of supporting packages that conform to the FSA standard, but package developers can make the choice to opt out of such benefits if they choose.

Optimistic updates

Opening this issue to track discuss whether FSA should address optimistic updates. If it does, I think it should be as an extension of the core spec.

Optional payload/meta properties

payload: Payload
and
meta: Meta
are not defined as optional properties (with "?")
yet they are supposed to be optional. I have not been able to get this to work without explicitly null values; is there a way to have an action with only a type, or are these fields not optional?

`ErrorFSA` type alias is incorrectly formatted

This is pretty minor and trivial, but should be addressed nonetheless. It seems that the entirety of the type definitions use the order of <Type, Payload, Meta> (or equivalent). However, ErrorFSA was not updated to use this new order.

That being said... I don't really understand why the ordering was changed... With this new ordering, all apps that use flux-standard-action now are required to define a type if they want to define a Payload or Meta. For many codebases, the type will remain as string. In my company's codebase - we have had to add a string to almost every instance of FSA (and derivatives).

It seems really weird that the only type that has a value used so commonly that it gets a default should be forced to be first. It being last makes the most logical sense imo; if you want to define just a Payload or Meta, you are not forced to also add a string that would otherwise be set by default.

Flow equalent

There is typescript but it were cool when flow were supported too

An in-range update of eslint-config-airbnb-base is breaking the build 🚨

Version 11.2.0 of eslint-config-airbnb-base just got published.

Branch Build failing 🚨
Dependency eslint-config-airbnb-base
Current Version 11.1.3
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As eslint-config-airbnb-base is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ

Status Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Adding types with optional properties made required

Properties payload, error, and meta are all optional properties according to documentation. However I believe there are cases where actions may need to make these properties required ( such as actions based around a text search ). Adding interfaces such as those suggested by @dsanders1234 in a previous issue about these options not being correctly typed as optional strikes me as a good approach, and I'm thinking of doing something similar as a workaround. The standard FluxStandardAction could remain in place while those additional versions could be used as needed.

In case of error, should meta be enforced?

This is a TypeScript question.

If I define an action expected certain meta, if the action is an error, should the error action still enforced that there should be a meta?

Request: isErrorAction utility function

Hello,

I have isErrorAction and isNotErrorAction functions in my codebase and thought it would be nice to have them in the FSA package.

There is isFSA function so these are nice additions to it.

My use cases are epics and reducers.

Should I create PR adding these?

function isErrorAction(action) {
    return action.error;
}

function isNotErrorAction(action) {
    return !isErrorAction(action);
}

Minimal cross-framework standard

Continuation of our discussion from Reactiflux -

I like what you're trying to do here, but I think what you have maps more closely to what you've built in Flummox than you intend, and doesn't do a good job of describing how other Flux frameworks behave, which limits its utility as a potential interop standard and makes the name not as descriptive as it could be.

For example, you specifically privilege status, while it's not at all standard for Flux frameworks to have a concept of action status as separate from the action itself - neither Alt nor Marty have specific concepts of success/failure actions and just have those treated as actions with different constants.

As I see it, there are really 3 types of data on an action -

  1. Type/constant: identifies the relevant handler for the action
  2. Payload: user-specified contents of the action
  3. Metadata: framework-level information regarding action

I'd probably organize the spec rather like:

{
  type,
  payload,
  metadata
}

I'd specify:

  • type: Something potentially appropriate as an object key, either a name string, a mangled name/ID string, or an ES6 Symbol - this should be sufficient to uniquely set up handlers
  • metadata: Framework-specific values not generated directly by the user - these can be things like original name of the action (in case it was mangled to dedupe), semantic action status for frameworks that explicitly model this (again, most frameworks do not), or other logging/diagnostic flags, or things useful for middleware
  • payload: As close as possible to what the user directly specified

I can see where you're going with specifying status as a special thing, but for my tastes, it's too opinionated. I understand that you feel that it makes sense to Flux frameworks to have semantic notions of action status, and I can see the arguments you've made in that regard, but it's not suitable to insert this as part of what aims to be a "minimal, common standard" when other frameworks often do not express or capture that notion in this way - and moreover when there exists a more generic abstraction (i.e. the metadata) that can capture similar framework peculiar things in a way that makes it clear where the potential interop barriers sit.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.