It would be nice to be able to use curried action creators in the props.
For example:
(Field is a simple reusable input component that calls props.onChange with the user's input)
const Form = ({ fields, setField }) => (
<div>
{fields.map(({ name, value }) => (
{/* preload setFiled with the field name */}
<Field onChange={setField(name)} />
)}
</div>
);
const setField = curry((name, value) => { type: 'SET_FEILD', name, value });
const mapStateToProps = ({fields}) => ({fields});
const mapDispatchToProps = { setField };
export default connect(mapStateToProps, mapDispatchToProps)(Form);
I like this because Field doesn't need to be aware of name, so it's more flexible and reusable.
Getting error Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
This is happening because redux's bindActionCreators wraps the creator like this:
(...args) => dispatch(actionCreator(...args))
so it tries to dispatch the curried function right away.
https://github.com/reactjs/redux/blob/master/src/bindActionCreators.js#L4
Should post this issue there instead?
There is this workaround, simple in this case because I only need to preload one argument.
{fields.map(({ name, value }) => (
<Field onChange={value => setField(name, value)} />
)}
@lazopm From your example above it looks like you need to wrap your curry function after your action creator is wrapped with the dispatch function instead of having the dispatch wrapper (provided by bindActionCreators) wrapped around your curried function. So when you add your event listener and call your setField function to take in the name parameter, it returns the dispatch function instead of calling dispatch right away with an invalid input (name argument in your case).
Something like this should do the trick:
const Form = ({ fields, setField }) => (
// Now that `setField` is already wrapped with dispatch, you
// can apply the `curry` function here
const curriedSetField = curry(setField);
<div>
{fields.map(({ name, value }) => (
{/* preload setFiled with the field name */}
<Field onChange={curriedSetField(name)} />
)}
</div>
);
// Here I removed the `curry` wrapper you have above
const setField = (name, value) => { type: 'SET_FEILD', name, value };
const mapStateToProps = ({fields}) => ({fields});
const mapDispatchToProps = { setField };
export default connect(mapStateToProps, mapDispatchToProps)(Form);
Correct, this is just an order of operations issue.
Most helpful comment
@lazopm From your example above it looks like you need to wrap your
curryfunction after your action creator is wrapped with the dispatch function instead of having the dispatch wrapper (provided bybindActionCreators) wrapped around your curried function. So when you add your event listener and call yoursetFieldfunction to take in thenameparameter, it returns the dispatch function instead of callingdispatchright away with an invalid input (nameargument in your case).Something like this should do the trick: