Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field extensions #264

Closed
wants to merge 6 commits into from
Closed

Field extensions #264

wants to merge 6 commits into from

Conversation

nmay231
Copy link
Collaborator

@nmay231 nmay231 commented Feb 20, 2020

Please check if the PR fulfills these requirements

  • The commit message(s) are descriptive of the changes made
  • The PR contains changes that are focused and differs from other PRs
  • Tests for the changes have been added where needed
  • Docs have been added / updated

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)

Adds a config option extension that allows the user to add different "field extensions." The combineExtensions helper allows the user to use multiple at once.

Included is the much requested flattenState and actionField.

What is the current behavior? (You can also link to an open issue here)

Requested in #179 and #233.

There are also WIP versions for helping with #150 and #237.

What is the new behavior?

Extensions would be added like so.

undoable(reducer, {
  extension: actionField({ insertMethod: 'inline' })
})

// alternatively, use combineExtensions to add multiple extensions
undoable(reducer, {
  extension: combineExtensions(
    flattenState(),
    actionField({ includeAction: (action) => action.included !== undefined })
  ),
  disableWarnings: true
})

disableWarnings disables the warnings that are logged by each field extension that describes how some state might be overridden.

Extension descriptions:

/**
 * The flattenState() field extension allows the user to access fields normally like
 * `state.field` instead of `state.present.field`.
 *
 * Warning: if your state has fields that conflict with redux-undo's like .past or .index
 * they will be overridden. You must access them as `state.present.past` or `state.present.index`
 */

/**
 * The actionField() field extension allows users to insert the last occuring action
 * into their state.
 *
 * @param {Object} config - Configure actionField()
 *
 * @param {string} config.insertMethod - How the last action will be inserted. Possible options are:
 *   - actionType: { ...state, actionType: 'LAST_ACTION' }
 *   - action: { ...state, action: { type: 'LAST_ACTION', ...actionPayload } }
 *   - inline: { ...state, present: { action: { type: 'LAST', ...payload }, ...otherFields } }
 *
 * @param {actionFieldIncludeAction} config.includeAction - A filter function that decides if
 * the action is inserted into history.
 */

Note when using flattenState: all the normal state is still there (.past, .index, etc.) but the user's present state is just copied down a level.

Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)

This should not break any existing code

Other information:

Docs still have to be updated. However, the readme probably needs a little cleanup anyways.

Docs have been added

@coveralls
Copy link

coveralls commented Feb 20, 2020

Coverage Status

Coverage increased (+0.6%) to 98.305% when pulling 0261d1d on field-extensions into 931b2ec on master.

@nmay231
Copy link
Collaborator Author

nmay231 commented Mar 11, 2020

@omnidan , I was able to add the docs, and this should be ready to merge as long as it looks good to you. It should definitely be squashed to not have all the annoying commits 😄

One thing to note, I removed some of the extraneous types like IncludeAction and just typed the functions directly. For some reason, CombineFilters (the type) was exported so I put a deprecation flag explaining to just use typeof combineFilters (the function). No code should break though.

Cheers 👍

Copy link
Owner

@omnidan omnidan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome PR and idea! Thanks for implementing field extensions. 😁

I was wondering whether we should put certain field extensions into the core redux-undo library or rather move them into a separate library/project? This would reduce the bundle size for those who do not use field extensions at all. What do you think?

I also noticed some field extensions are not documented and I think the disableWarnings option could be an argument to the field extension functions instead of a redux-undo wide option.

Otherwise this looks great and it will solve many issues people have had with redux-undo! 🎉

src/fieldExtensions.js Show resolved Hide resolved
return (undoableConfig) => {
console.log(undoableConfig)
if (!undoableConfig.disableWarnings) {
console.warn(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should only show this warning if we detect that the state contains one of redux-undo's field names, or an array/primitive?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that. The issue is you would be checking the returned object for every action that was dispatched to the wrapped reducer (there is no way to check only the first time and then trust it from then on).

I thought it would be best to warn the user exactly once at initialization, no matter what the user has in their state. It should also be very clear in the documentation that this is the case (I can make it more explicit).

Thoughts?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I see, that makes sense. then let's keep it as is but put the disableWarnings option as an argument to the function. let's also separate the field extensions into a separate package.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good 👌


if (!undoableConfig.disableWarnings) {
console.warn(
'Warning: the actionField() extension might override other state fields',
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also here, should we only warn when we detect that it is overriding something?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same idea as above.


// istanbul ignore next: This will be put on hold for now...
// eslint-disable-next-line no-unused-vars
const nullifyFields = (fields = [], nullValue = null) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

document these in README as well?

do you think the field extensions should be part of redux-undo core, or maybe a separate library? I don't think everyone will need it and it slightly increases the bundle size

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had briefly mentioned in the PR description that these were WIP and would come out soon, but I realize that it is silly to leave them there. I'll remove them until they are fully implemented. 👍

As for separating them into a different package, that sounds like a good idea! They are purposely optional and, yes, not everyone needs it in their bundle (though tree-shaking is starting to mitigate the problem).

@@ -90,6 +90,8 @@ export default function undoable (reducer, rawConfig = {}) {
neverSkipReducer: false,
ignoreInitialState: false,
syncFilter: false,
extension: () => (state) => state,
disableWarnings: false,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be an argument to the extension function instead of a redux-undo wide config

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that.

@nmay231 nmay231 closed this Mar 18, 2020
@nmay231 nmay231 deleted the field-extensions branch March 18, 2020 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants