-
Notifications
You must be signed in to change notification settings - Fork 33
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
Feat: add useStateMachineInputs hook #310
base: main
Are you sure you want to change the base?
Feat: add useStateMachineInputs hook #310
Conversation
src/hooks/useStateMachineInputs.ts
Outdated
initialValue?: number | boolean; | ||
}[] | ||
) { | ||
const [inputs, setInputs] = useState<StateMachineInput[] | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you think about removing the union with null and having inputs only be StateMachineInput[]
?
I think an empty array is a simpler api to deal with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that definitely seems like a better option. I'll change that!
src/hooks/useStateMachineInputs.ts
Outdated
if (!rive || !stateMachineName || !inputNames) { | ||
setInputs(null); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this necessary? It seems the next lines are checking the same and the else statement is also handling the alternate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it doesn't seem necessary to me either, but I had that in because I found the same logic in the useStateMachineInput
code.
I could create another pull request to refactor the useStateMachineInput
hook if you're okay with it.
I'll work on removing some of the repeated logic.
src/hooks/useStateMachineInputs.ts
Outdated
} | ||
setStateMachineInput(); | ||
if (rive) { | ||
rive.on(EventType.Load, () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for safety, the useEffect hook can return a clean up function to clear this callback.
If not, multiple instances of the function might try to set the input values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll add a rive.off()
cleanup function.
thanks for the PR! looks good overall, just left some comments on some details. |
Thanks for the PR! Right now this is how you'd use it, right?
I'd love to see it to where defining each input didn't require extra component code. Maybe something like:
|
Does anyone else get this warning when using it in a component: |
src/hooks/useStateMachineInputs.ts
Outdated
const selectedInputs = inputs.filter((input) => | ||
inputNames.some((inputName) => inputName.name === input.name) | ||
); | ||
if (selectedInputs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this validation isn't needed, a filter call will always return an array at this point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True! I'll fix that too!
I just needed them to be fired all at once so I didn't have to manage them one by one. |
I'll take a look at it! |
I made some changes to the code! 2a26db1
|
src/hooks/useStateMachineInputs.ts
Outdated
initialValue?: number | boolean; | ||
}[] | ||
) { | ||
const [inputMap, setInputMap] = useState<Map<string, StateMachineInput>>(new Map()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason why the map needs to be stored in the state instead of the array?
It's great that it is being used as an intermediate store while building the inputs for performance, but that seems like an implementation detail of syncInputs
.
In the end it's exposed as an array and It forces to use the useMemo hook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope not at all anymore.
It was a Map
for the initial implementation I planned, which is returning the Map
instead of an Array
. I thought it would be a better implementation as the user gets to choose which input they want to use, without having to map over the whole array again to find it.
But I realized that could be handled by preprocessing the inputNames
array passed to the hook. ex) filtering out the unnecessary inputNames before calling the hook.
So yeah, there's no reason for it to be a Map
instead of an Array
now.
I'll change that! Thanks for pointing it out!
) { | ||
const [inputMap, setInputMap] = useState<Map<string, StateMachineInput>>(new Map()); | ||
|
||
const syncInputs = useCallback(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of curiosity, in the previous implementation this method was defined in the useEffect hook directly. Was there a reason for moving it outside?
As far as I know, it's a good practice to declare methods that are only used in a useEffect, inside the useEffect hook itself. It helps with encapsulation. And in this particular case doesn't need the useCallback hook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true that declaring functions that are only used in a useEffect within the hook is helpful for encapsulation, but I think it kind of hurts the readability of the code in many cases.
I personally like to leave the useEffect hook as concise as possible so that I can understand the flow of the useEffects quickly without scrolling up and down too much.
(Besides, I find useEffects to be where the majority of unexpected bugs occur, so I try to keep them easy to understand in most cases.)
Since there's just one useEffect in this case, and since the function gets recreated whenever the useEffect runs (as they have the same dependency array), I don't really mind whether the function is defined inside or outside the hook.
If putting functions within useEffects is the convention Rive follows, I'm more than happy to move it back into the useEffect! Let me know what you think!
@lancesnider Are you still seeing this warning? I don't seem to be getting it right now from where I'm using it. |
Add new
useStateMachineInputs
Hook for fetching multiple stateMachine inputs from a rive fileDescription
This pull request introduces a new hook,
useStateMachineInputs
, designed to easily get multiple inputs from a variable number of inputNames.Previously, you had to
map
over the inputNames array to create input for each of them.Since that behavior is against the rules of hooks, I decided to create this new hook.
This would be against the rules of hooks.
const inputs = inputNames.map(inputName => useStateMachineInput(rive, stateMachine, inputName));
With this hook, you can do it this way.
const inputs = useStateMachineInputs(rive, stateMachine, inputList);
Changes Made
Created
useStateMachineInputs.ts