pauldijou / redux-act Goto Github PK
View Code? Open in Web Editor NEWAn opinionated lib to create actions and reducers for Redux
License: Apache License 2.0
An opinionated lib to create actions and reducers for Redux
License: Apache License 2.0
Do you have a quick code sample you can show that implements CRUD usage? Or really, any LOAD and UPDATE usage is fine. I'm not sure if the typical redux actions of MODEL_CREATE_REQUEST, MODEL_CREATE_SUCCESS, MODEL_CREATE_ERROR still apply when using redux-act. If so, how, and if not, well...how?
Hey there,
I have a case where I can't be sure if my reducer will be instantiated with an array or an object. I'd like to coerce the array into an object if necessary.
It would look something like this (in vanilla redux):
function myReducer (state={}, action) {
var newState = {}
if (Array.isArray(state)) {
state.forEach(function(item){
newState[item.id || bsonId()] = item
});
} else {
newState = state
}
if (action.type === 'HELLO WORLD') {
return {newState, hello: 'world'}
}
// etc....
return newState
}
I couldn't think of a way to dynamically set the default reducer value with redux-act. Do you have any suggestions for how to do this? Maybe the create reducer api needs to be expanded slightly?
const reducerMap = createReducer({
[increment]: (state) => state + 1,
[add]: (state, payload) => state + payload
}, function(initialValue){var newInitialValue = {} ...etc.... return initialValue });
Thanks!
Thomas
I'm trying to test an Angular 1.x app which is using redux-act. The problem is that when I run unit tests, redux-act throws a tantrum saying that I have duplicate action types in my code.
When tests are run, services keep re-initializing and call same reduxAct.createAction
multiple times, which results in "Duplicate action type: XXX" due to this line.
Wouldn't it be a good idea to expose types
as a public property or to have some kind of a hasType
/clearAllTypes
API that could be called on afterEach
in tests?
Hi,
I have a state that looks like:
cart:
"ITEMKEY123":
product: {product meta here }
qty: 1
I would like to when adding an item in the "cart" to check if the key exist and then if it already exist, update the qty.
My actions look like:
export const addToCart = createAction('ADD_TO_CART',( product, qty ) => {
return { product, qty };
});
My Reducer looks like:
export default createReducer({
[actions.addToCart]: (state, {product, qty}) => {
return u({
[product.$key]: {
product: product,
qty:qty,
tax_rate: product.tax_rate,
sale_price:product.sale_price,
}
}, state)
},
}, state = {});
I figured I would search for the key in the state and if present change the qty
of the object.
But if I do something like:
state.indexOf(product.$key)
I get
State.indexOf is not a function
In vanilla redux, you can write a reducer:
(state, action) => {
switch (action.type) {
case "SOME_ACTION": return {...state};
default: return {...state, someOtherThing: 3}
}
}
What is the equivalent of this 'default' action handler in redux-act?
Is there a way to specify multiple action creator triggers for one function in createReducer?
createReducer({
[actionOne] OR [actionTwo]: (state, payload) => doSomething(state, payload),
}, defaultState)
... or do I have to repeat code for every one of them?
createReducer({
[actionOne]: (state, payload) => doSomething(state, payload),
[actionTwo]: (state, payload) => doSomething(state, payload),
}, defaultState)
You get this kind of behavior easily with fallthrough for the standard switch-based reducer...
I had a great idea for binding the actions functions to both a store, and another function to send the payloadedAction over a websocket. But experimenting with it, I had to wonder if this functionality works as intended, or if I'm using it wrong?
// in an Actions file
assignAll(Actions, [console.log.bind(console, 'Foo: '), store])
//when an action is triggered, our logger fires
Foo: Object {type: "SET_STATE", payload: "SET_STATE", meta: Object}
// but the action has been dispatched (or reduced) in a weird way
store.getState()
Object {0: "S", 1: "E", 2: "T", 3: "_", 4: "S", 5: "T", 6: "A", 7: "T", 8: "E", game: Object, players: Array[0], round: Object}
Full source is here: https://github.com/deanius/react-trivia/tree/bindActionIssue
Hi,
Is it supported, and is there an example of reducer and action reuse with redux-act?
For example, if I defined counterReducer
twice in combineReducers
.
combineReducers({
counter1: counterReducer,
counter2: counterReducer
})
Is it possible to dispatch an action to target a specific reducer without duplicating action creators and reducers?
It seems there are not any available typings for this library, which is quite a shame as it looks quite nice.
Right now it seems actions are always tied to their respective reducers. Actions can be re-used, but their reducing functions have to be duplicated. Is there any way that reducing functions could be tied to an action from the get go?
I'm comparing the two to try to think of which to use. The syntax is similar, but i know the internals vary. Wondering if you can provide some insight on how this library differs most prominently from https://github.com/acdlite/redux-actions
Would it be possible to extend the batch method to accept an optional description to use instead of (or appended to) "Batch"? This would improve readability of logs where multiple distinct batch actions are being dispatched.
export default createReducer<typeof defaultState>({}, defaultState)
.on(setCanCount, (state, payload) => ({
...state,
canCount: payload
}))
.on(someOther, (state, payload) => ({
...state,
...payload
}))
import { createAction, createReducer } from 'redux-act'
export const j5success = createAction('J5_SUCCESS')
export const j5start = createAction('J5_START')
export const j5fail = createAction('J5_FAIL')
I would have expected the above actions to plain strings as their output without any appended id. Aka createAction('J5_START')
should yield an action with type 'J5_START'.
Instead this is what I'm seeing:
I've started using this for a new project and I should say, I love it!
However currently have an issue when I'm asserting the action type of an action created by redux-act
.
I can see that createAction
is creating a unique type for the action in the format of [0] name of action
with 0
being any number.
Unlike traditional redux where action types are hand picked, here we cannot predict (or control at test time) the exact name that is chosen for an action and hence not able to assert it.
Any view on this?
Hey there,
I'm not able to get my reducer made using createReducer
to respond to outside actions. I'm not sure if I'm doing something wrong. Here's my code:
//./caretPosition.js
import { createAction, createReducer } from 'redux-act'
// ------------------------------------
// Actions
// ------------------------------------
export const clearCaret = createAction('clearCaret')
export const updateCaret = createAction('updateCaret')
var { updateSelectionLayer } = require('./selectionLayer'); //important, keep this here in the order of the file and let it use the commonjs syntax!
// ------------------------------------
// Reducer
// ------------------------------------
export default createReducer({
[updateSelectionLayer]: () => {
//clear the caret if the selection layer is updated!
return -1
},
'redux-form/INITIALIZE': (state) => {
debugger;
return state
},
['@@INIT']: (state) => {
debugger;
return state
},
[clearCaret]: () => {
return -1
},
[updateCaret]: ({start}, payload) => {
return payload
},
}, 0)
in the above code, neither 'redux-form/INITIALIZE' nor '@@init' are triggering the debugger, but the [clearCaret] works fine.
Am I missing something here?
Thanks!
Thomas
For example, I have this action creator init()
, and I can't know the state when I dispatch it. In a normal action creator, I could return a function (dispatch, getState)=>{}
.
The main use case for this is api/socket calls that are based on the current state of the app. There's usually workarounds except in a specific case I'm dealing with.
Sorry, but I didn't understand how to use that.
Can you please give an example ?
Thanks!
o/ @pauldijou
First of all, thanks for this amazing library :)
I'm opening this issue so we can discuss createReducer's default state mutability.
Recently, I accidentally updated my default state from within a reducer function, effectively creating a memory leak.
Similarly to the following piece of code:
const addItem = createAction('Add an item');
const initialState = {
foo: {
items: [],
},
};
createReducer({
[addItem]: (state, payload) => {
const items = state.foo.items;
items.push(payload);
return {
foo: {
items,
},
};
},
}, initialState)
Because I use redux in a node.js web application, a store is created for every HTTP request it receives, and so, every new store, that was created as HTTP requests were handled, had a default state that was updated from the previous request.
So, that's for my mistake - I miss working with you by the way, you probably never would have let me do such a rookie mistake.
Naively, I think redux-act probably could help the developers not do the same mistake I did.
Indeed, this would have never happenned if the createReducer
function either:
I would never have updated the default state object, though I probably would never have noticed that I was wrongly using redux update pattern.
I would have never been able to modify the default state object, it would have failed silently, or thrown a TypeError if I was doing 'use strict' in my reducer function.
Now, I understand that it's the developer's responsability to not mutate the default state and JavaScript is mutable by default, but as redux-act is an opiniated lib aiming at making redux less error-prone, I was thinking that, maybe, redux-act could help me on this.
Let me just quote the project's FAQ
You never know what the new dev on your project might do... Maybe (s)he will not realize that [...] and now everything is broken and a wormhole will appear and it will be the end of mankind. Let's prevent that!
What do you think?
Thanks for reading :)
Useful reading on the topic, for those it may concern:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html
Hi @pauldijou, would you accept a PR do do this?
const reducer = createReducer(on => {
on([action1, action2], (state, payload) => {
// do stuff
})
});
Hi,
When use redux-act with next.js in my project, after page changes i receive this error:
TypeError: Duplicate action type: REQUEST_PAGES
at check (/home/xxx/www/ucavtor/node_modules/redux-act/lib/types.js:33:11)
at createAction (/home/xxx/www/ucavtor/node_modules/redux-act/lib/createAction.js:50:22)
at Object.<anonymous> (/home/xxx/www/ucavtor/site/actions/pagesActions.js:17:29)
at Module._compile (module.js:660:30)
at Module._compile (/home/xxx/www/ucavtor/site/node_modules/source-map-support/source-map-support.js:492:25)
at Object.Module._extensions..js (module.js:671:10)
at Module.load (module.js:573:32)
at tryModuleLoad (module.js:513:12)
at Function.Module._load (module.js:505:3)
at Module.require (module.js:604:17)
I think that problem is in HMR.
have someone any idea how i can fix that? At this moment i restart server after any changes.
I could not run assignAll after I added an async function.
Uncaught TypeError: actions[action].assignTo is not a function
Do I have to manually call dispatch on my async functions?
Here is some idea of API for async actions creation:
import {createAction, createAsyncAction} from 'redux-act';
// createAsyncAction 1st argument is function that returns promise.
const fetchComments = createAsyncAction((id) => {
return fetch(`api/post/${id}/comments/`);
});
// action will be used like fetchComments(41);
// reducer will have .onAsync method and it'll be called 2 times
// 1st time with loading = true and empty err / result
// 2nd time with loading = false and error or result data basing on if promise was rejected or not
reducer.onAsync(fetchComments, (state, loading, error, result) => {
return {
...state,
comments: {
loading,
error,
result
}
}
})
// leter on I can:
fetchComments.asignTo(store);
fetchComments(42);
What do you think?
Hi, I found you library very similar to my vision. I'm going to make some improvements to API and behaviour, if you open to request, I wiil be glad to contributing to you project
Does anyone know how to type this properly -
Line 86 in 8322d80
I've tried with various methods, but couldn't figure out how to type return value of createAction
, maybe somebody here got better luck.
As I understood off
function in createReducer
is supposed to remove some action handler on some condition. In my opinion this is wrong approach because this should be handled by state.
Instead of writing:
const reducer = createReducer(function (on, off) {
on(increment, state => {
// Just for fun, we will disable increment when reaching 2
// (but we will still increment one last time)
if (state === 2) {
off(increment);
}
return state + 1;
});
}, 0);
we should write:
const reducer = createReducer(function (on, off) {
on(increment, state => state > 2 ? state : state + 1);
}, 0);
I do not see other off
usages.
Removing off
will allow to simplify createReducer
signature to:
const reducer = createReducer(increment, state => state > 2 ? state : state + 1, 0);
Consider following situation:
import {createActionAsync} from 'redux-act-async' // https://github.com/FredericHeem/redux-act-async
const create = createActionAsync('CREATE', createUser)
const update = createActionAsync('UPDATE', updateUser)
const initialState = {
saving: false
}
const reducer = createReducer(function (on) {
on(create.request, update.request, (state) => ({
...state,
saving: true
}))
}, initialState)
Is there any possibility of spreading ...payload
to the reducer by default?
Having the change in syntax between single and multiple arguments is inelegant:
const foo = createAction('foo');
const bar = createAction('bar', (...args) => args);
const reducer = createReducer({
[foo]: (state, a) => {...},
[bar]: (state, [a, b, c]) => {...}
});
dispatch(foo('a'));
dispatch(bar('a', 'b', 'c'));
Whereas it would be really killer to have the 1:1 correspondence. Maybe it is just me, but this is what I intuitively thought would happen before I read the docs.
const foo = createAction('foo');
const bar = createAction('bar');
const reducer = createReducer({
[foo]: (state, a) => {...},
[bar]: (state, a, b, c) => {...}
});
dispatch(foo('a'));
dispatch(bar('a', 'b', 'c'));
This is completely backward compatible.
I was trying to use the logger as documented with Redux logger however I got a 'Cannot read property 'reduxLogger' of undefined.
Looking at the source code it seems that logger might be incorrectly exported?
export { default as loggers } from './loggers';
Since logger is in its own folder now, I'm guessing this is just an update that needs to be made?
const isSerializable = (typeof description === 'string') && /^[A-Z_]+$/.test(description)
I notice this calls only CONSTANT_STYLE strings serializable. However, I'm starting to think that I want to name my actions differently, for example, actions that affect the game
key of the state could be called game.begin
/game.end
.
Is there a reason for keeping things so locked down to the Abramov-school of action types? Or can this library enable some broader conventions ? Curious for your thoughts, my want would be to permit valid JS identifiers, or a few of them separated by dots. The CSS-ers may also want to allow dashes.
In English, the past tense of bind is bound.
o/ @pauldijou
I was wondering if you would consider adding a new babel plugin to transform Object.assign
to a inline helper,
as it's an es2015 feature and the browser support, though ~correct, is not wide enough to be safely used in production.
We've been dodging this issue by patching globals so far, but we'd like to move away from that.
More than happy to open a PR to make use of transform-object-assign, or discuss this further :)
Thank you for your time,
I am using https://github.com/milankinen/livereactload for hot reloading my code during development. And I am using redux-act with serializable actions so I can store reliably export and import my state with the dev tools during development.
Trouble is: When my code get's reloaded, it throws TypeError: Duplicate action type
, because actions are added again. Like most hot reloading solutions, livereactload offers a hook to run on reload but those hooks are run after the module is ran, so the error is already thrown and using types.clear()
in the hook would be too late.
Any idea how to solve this?
It is does not work:
if (module.hot) {
module.hot.accept('src/ducks', () => {
// Disable all type checking meaning you can now have several actions
// with the same type. This is needed for HMR (Hot Module Replacement)
// but never never never enable it in production
types.disableChecking();
const nextRootReducer = require('src/ducks/index').default;
store.replaceReducer(nextRootReducer);
// Set back type checking
types.enableChecking();
});
}
I see error:
[HMR] TypeError: Duplicate action type
Please give to me example.
redux-act
appears to adhere to the Flux Standard Action spec, except that there's no way to add error: true
to error actions.
Is this something you would be open to adding?
Starting to use your wonderful library. Have only done basic Redux so far, but already hate all the boilerplate.
I was wondering if you had an example or two on the purpose of metadata in actions and reducers? I understand it's for "extra" data that isn't explicitly needed for the action. However, Redux (http://redux.js.org/docs/basics/Actions.html) seems to make no mention of it. And, I've seen it mentioned else, but haven't found an example of its use.
Could you give tangible and/or real-world example of metadata and its applicability?
Hi @pauldijou. Your approach for createReducer
looks like Bacon.update
I write some description text in develop envirnment, but I don't want it appear in dist files.
Hey man, thanks for the library! I was wondering how we can handle simple conditionals like these
function middleware (stuff) {
return ({ dispatch }) => next => action => {
if (action.type === SOME_ACTION) {
// do something
}
}
}
A createReducer
seems not appropriate for the use case here.
I chose redux-act VS redux-actions for this reason.
The following code fails for me from the typescript compiler.
import {loggers} from 'redux-act';
the error is: Module 'test/node_modules/redux-act/types' has no exported member "loggers"'
Hey there,
I've recently been dealing with a strange issue caused by circular dependencies where the action creator I pass into createReducer actually turns out to be undefined: https://github.com/erikras/ducks-modular-redux/issues/24
I know it isn't the most likely scenario, but I think it would be a good sanity check if redux-act would throw an error if one of the action creators it is handling is undefined.
For example, this doesn't throw any error:
createReducer({
[undefined]: () => {
return {
hello: 'world'
}
}, {})
Let me know what you think,
Thanks!
Thomas
I'm interested in using this in a JSBin to show off how cool it is. The issue is the file provided by https://npmcdn.com/[email protected] does not bring the needed functions to the browser. I imagine some build task could browserify it but I thought i'd ask and see how that sounds first.
If I send a action with no register in reducer, How to catch it in redux-act
?
Normal:
switch (action.type) {
case 'MY_ACTION':
// ...
default:
// I need process this
return formReducer(state, action)
}
Redux act
createReducer({
MY_ACTION: () => {},
???
})
Hi, I'm wondering if this is a general pattern:
After creating a reducer via combineReducers
, where each sub-reducer minds its own part of the state tree, I want to apply some preReducers
that do 'global' state mutations and which pre-empt the behavior of the others. I've written this code:
(origReducer, preReducers = []) => {
// return a reducer which calls origReducer only if none of the prereducers has changed the state
return (state, action) => {
for(let reducer of preReducers) {
let newState = reducer(state, action)
if (newState != state) return newState
}
return origReducer(state, action)
}
}
My question is do you think this is deserving of its own name or case in this library? Example use cases are global reducers that might move parts of the state tree around, or otherwise break the narrow guidelines laid down by combineReducers
. Thanks, Dean
Hi gyes.
It seems that you need to correct your code right here.
// Little bonus, if you need to support metadata around your action, // like needed data but not really part of the payload, you add a second function const metaAction = createAction('desc', arg => arg, arg => {meta: 'so meta!'});
Transpiler compile it to something like that
var metaAction = createReducer('desc', function (arg) {
return arg;
}, function (arg) {
meta: 'so meta!';
});
So I assume that you forget the braces because you need to make it expression.
Something like this.
arg => ({meta: 'so meta!'})
I was using them and enjoying them, but then I read this:
Is this an issue I will face later on, when I do SSR?
Hey there,
I'm currently using redux-act in a small project and finding it to be very nice to work with. I like how little boilerplate needs to be written, which in turn makes things all the more easier for me to understand.
That said, I haven't used it on a larger/more complex project, and I'm wondering if there are any downsides to using the redux-act approach? I know that it is all redux under the hood, but I'm mostly worried about compatibility issues, like other libraries or patterns that can't be used in conjunction with the redux-act way of creating reducers/actionsCreators.
Thanks for the library and your advice,
Thomas
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.