Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

[react-form | DynamicList] add reset function and dirty state #1828

Merged
merged 1 commit into from
Apr 21, 2021

Conversation

oluwatimio
Copy link
Contributor

@oluwatimio oluwatimio commented Apr 9, 2021

Description

Fixes #1830 and part of https://github.com/Shopify/core-issues/issues/23975

There is no reset ability for dynamic list or flag to know if the dynamic list is dirty. This means if for example we are using a context bar and click discard, the dynamic list new field will still persist.

This PR adds the ability to reset to the initial list state and to know if the dynamic list is dirty.

It also adds the ability to add multiple dynamic lists

co-authored with @sylvhama

Tophat

Code sandbox here .

Type of change

  • react-form/dynamic-list Minor: New feature (non-breaking change which adds functionality)

Checklist

  • I have added a changelog entry, prefixed by the type of change noted above (Documentation fix and Test update does not need a changelog as we do not publish new version)

@oluwatimio oluwatimio requested a review from a team April 9, 2021 00:32
@oluwatimio oluwatimio changed the title [react-form | DynamicList] add reset function and dirty state WIP [react-form | DynamicList] add reset function and dirty state Apr 9, 2021
@oluwatimio oluwatimio marked this pull request as draft April 9, 2021 00:33
@kaelig
Copy link
Contributor

kaelig commented Apr 9, 2021

👋 Thank you for the PR!

Please run:

git pull origin main --rebase && git push origin dynamic-lists/add-reset-and-dirty-state --force

to get the latest changes and fix the failing test, apologies for the inconvenience.

@oluwatimio oluwatimio force-pushed the dynamic-lists/add-reset-and-dirty-state branch from 2c86b17 to 452f2f9 Compare April 9, 2021 14:28
@oluwatimio oluwatimio changed the title WIP [react-form | DynamicList] add reset function and dirty state [react-form | DynamicList] add reset function and dirty state Apr 9, 2021
@oluwatimio oluwatimio marked this pull request as ready for review April 9, 2021 17:34
@oluwatimio oluwatimio force-pushed the dynamic-lists/add-reset-and-dirty-state branch from 6b447e7 to e3e9901 Compare April 9, 2021 18:01
Copy link
Contributor

@sylvhama sylvhama left a comment

Choose a reason for hiding this comment

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

I have tested locally via yalc and it does not fix #1830
It seems useForm is not aware that the dynamic list is dirty. If I add a new item the form remains not dirty. Plus when I press reset I would expect that the list becomes empty again but it does not.

packages/react-form/src/hooks/list/baselist.ts Outdated Show resolved Hide resolved
packages/react-form/src/hooks/list/baselist.ts Outdated Show resolved Hide resolved
@oluwatimio oluwatimio removed the request for review from michenly April 12, 2021 14:17
@oluwatimio oluwatimio marked this pull request as draft April 12, 2021 14:17
@oluwatimio
Copy link
Contributor Author

With this commit 8a4cfa7 we can now reset and get the dirty state of the dynamic list from the forms reset and dirty state

@sylvhama sylvhama mentioned this pull request Apr 13, 2021
2 tasks
@oluwatimio oluwatimio force-pushed the dynamic-lists/add-reset-and-dirty-state branch from 0cd4a61 to 310bf01 Compare April 14, 2021 15:23
@oluwatimio oluwatimio marked this pull request as ready for review April 14, 2021 15:24
@oluwatimio
Copy link
Contributor Author

oluwatimio commented Apr 14, 2021

PR now ready for review. Resetting lists in a listbag with the form's reset function should now be possible with dynamic list or any type of list created in the future. Same case for dirty.

@oluwatimio oluwatimio requested a review from michenly April 14, 2021 15:27
@michenly michenly removed their request for review April 14, 2021 16:25
Copy link
Contributor

@sylvhama sylvhama left a comment

Choose a reason for hiding this comment

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

My biggest concern is the comment about export interface ListBag.
Otherwise it looks good, I have not checked all the tests since we might update several stuff first.

packages/react-form/README.md Outdated Show resolved Hide resolved
packages/react-form/README.md Outdated Show resolved Hide resolved
packages/react-form/README.md Outdated Show resolved Hide resolved
packages/react-form/CHANGELOG.md Outdated Show resolved Hide resolved
packages/react-form/src/hooks/form.ts Show resolved Hide resolved
packages/react-form/src/hooks/list/baselist.ts Outdated Show resolved Hide resolved
packages/react-form/src/hooks/list/baselist.ts Outdated Show resolved Hide resolved
packages/react-form/src/types.ts Outdated Show resolved Hide resolved
packages/react-form/src/hooks/listdirty.ts Outdated Show resolved Hide resolved
packages/react-form/src/types.ts Outdated Show resolved Hide resolved
@oluwatimio oluwatimio force-pushed the dynamic-lists/add-reset-and-dirty-state branch from 27987cb to 8b945c1 Compare April 15, 2021 17:34
@oluwatimio oluwatimio requested a review from sylvhama April 15, 2021 17:34
Copy link
Contributor

@marutypes marutypes left a comment

Choose a reason for hiding this comment

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

One thing I noticed that was already there, an a comment about some readability concerns, but otherwise this is looking pretty nice to me! I didn't tophat, but I'm happy to have this API in the library.

const fieldsRef = useRef(fields);
fieldsRef.current = fields;
const fieldsRef = useRef(fieldsWithLists);
fieldsRef.current = fieldsWithLists;
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this was already here, but a note on the pattern:

This technically works but may stop working in future react updates. We recently removed similar patterns in other hooks in quilt and are considering adding a lint rule. It might be best to find an alternative way of doing this as a result.

Actually, looking at it closer, since we update it literally every render, why can't we just use the value directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh yes I think we can get rid of the ref since we update it, Thanks! Will try that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noticing removing the ref causes the makeClean function to be re-created on every render so I switched to useLazyRef to avoid mutating refs directly during the render phase

packages/react-form/src/hooks/list/baselist.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@attila-berki attila-berki left a comment

Choose a reason for hiding this comment

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

LGTM, nice improvement of the form and the dynamic list 💯

Copy link
Contributor

@sylvhama sylvhama left a comment

Choose a reason for hiding this comment

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

I have tested it in web and it works! However I have noticed a typing issue that should be addressed before merging I think:
Screen Shot 2021-04-16 at 4 31 35 PM

In your codesandbox you use ! but I think consumers should not have to do this. We need to explore if we can tell TS to detect we have passed dynamic list(s) 🤔

packages/react-form/src/hooks/form.ts Outdated Show resolved Hide resolved
@oluwatimio
Copy link
Contributor Author

I have tested it in web and it works! However I have noticed a typing issue that should be addressed before merging I think:
Screen Shot 2021-04-16 at 4 31 35 PM

In your codesandbox you use ! but I think consumers should not have to do this. We need to explore if we can tell TS to detect we have passed dynamic list(s) 🤔

Hmm, I see 🤔 . It is because the parameter is optional that dynamiclist can be undefined in the forms return. We will always need to do this / check first.

It is like having a prop that can possibly be undefined, we will need to check if it is undefined before actually accessing this property. I am not sure I can see a way around this except retuning an empty dynamic list if dynamiclist param is undefined. I personally do not recommend masking the fact that it can be undefined just to avoid having to check.

@sylvhama
Copy link
Contributor

I think there must be a way e.g. https://www.typescriptlang.org/docs/handbook/2/conditional-types.html (I am not TS expert, this might not be the right thing to look at).

Also another problem comes to my mind, what if I only one to manipulate dynamic lists? then fields should become optional 😬

@oluwatimio
Copy link
Contributor Author

I have tested it in web and it works! However I have noticed a typing issue that should be addressed before merging I think:
Screen Shot 2021-04-16 at 4 31 35 PM

In your codesandbox you use ! but I think consumers should not have to do this. We need to explore if we can tell TS to detect we have passed dynamic list(s) 🤔

In my opinion, the point of the non-null assertion operator is to tell the TypeScript compiler that you already know the variable is not null. I dont see any disadvantages to using it if you know that the dynamic list was passed in

@oluwatimio
Copy link
Contributor Author

oluwatimio commented Apr 16, 2021

I think there must be a way e.g. https://www.typescriptlang.org/docs/handbook/2/conditional-types.html (I am not TS expert, this might not be the right thing to look at).

Also another problem comes to my mind, what if I only one to manipulate dynamic lists? then fields should become optional 😬

I am not sure but I think if we are to use a conditional type, wouldn't we still have to check what type it is before using the dynamic list? I personally don't see this being different to a prop being optional in react and having to check its defined before using it. Same thing for a gql query retuning an optional value and having to check. I am not sure where the problem lies because the user is in control of passing in the dynamic list so if they know it is defined, they can use the non null assertation which is what it was created for. The typescript docs says that here

@oluwatimio
Copy link
Contributor Author

oluwatimio commented Apr 16, 2021

Another thing I noticed is, if we are to change it from non-optional to required in the Form's interface, we will have a syntax error
Screen Shot 2021-04-16 at 5 19 59 PM

In this case, we may have to modify the parameter as well to be able to assign the dynamicList in the return. This means that we either make the parameter required (which will break everything in web) or we can assign a default value. Also, as for the field parameter, it is implied that we cannot use useForm without a field because the field parameter is required. I would probably suggest that if someone wants to use useForm and dynamic list without a field, they can use the optional way of initializing a dynamic list which is to pass the FieldDictionary as a field into the form (the way its currently being done). Then use the reset and dirty states of the dynamic list.

@oluwatimio
Copy link
Contributor Author

We discussed this and we will be returning an empty DynamicList bag when dynamicLists param is undefined. This will have no effect on computation in the form and will remove having to use the assertion operator or checking if dynamic list is defined.

@oluwatimio oluwatimio requested a review from sylvhama April 19, 2021 15:17
@oluwatimio oluwatimio force-pushed the dynamic-lists/add-reset-and-dirty-state branch 4 times, most recently from b42269d to 572b8a7 Compare April 19, 2021 16:46
@oluwatimio oluwatimio requested review from sylvhama and removed request for sylvhama April 20, 2021 13:05
@sylvhama
Copy link
Contributor

sylvhama commented Apr 20, 2021

Proposition to avoid default value for dynamicLists: #1848

@oluwatimio oluwatimio force-pushed the dynamic-lists/add-reset-and-dirty-state branch from b1223c7 to 79bb4b9 Compare April 21, 2021 19:43
test baselist

Update baselist.test.tsx

lint fix and additional tests

update tests

Update CHANGELOG.md

Update README.md

Update CHANGELOG.md

add dynamic list to the form

update comments

Update form.ts

add check for input since theres a possibility of adding undefined input dynamicListFields

Update baselist.ts

Update baselist.ts

added tests to form

Update form.test.tsx

fixed reset recreating on each render

Update listdirty.ts

Update README.md

Update README.md

Update README.md

added DynamicListBag

Update packages/react-form/README.md

Co-authored-by: Sylvain Hamann <[email protected]>

Update packages/react-form/README.md

Co-authored-by: Sylvain Hamann <[email protected]>

Update README.md

Update baselist.ts

docs

used lazy ref

fix docs

more improvement to docs

return default bag on undefined dynamic list

Update form.test.tsx

rebase gone bad fix

improve dynamicLists typing (#1848)

* improve dynamicLists typing

* revert to initial tests

* mock console.error to clean logs

* add dirty tests for dynamic lists

* update form tests

* remove useless file

Update dynamiclist.test.tsx
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

useDynamicList does not make the form dirty and has reset issues
5 participants