Proposal: Support Hooks
- Dominant language
- JavaScript
- Stars
- 42
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Description
Hooks is direction that React is going, regardless of any issues that some of us might have with them.
The API inspiration for our current project comes from recompose and redux; the recompose library is being discontinued in favor of hooks, and one of the primary redux developers was on the hooks project in order create redux-replacement hooks like `useReducer`. While redux is not being discontinued, it is no longer necessary. For this reason, I propose that we release ylem v3 that primarily supports hooks, though old apis are maintained and decprecated at `ylem/legacy`.
After reviewing how hooks work, I think doing this would greatly simplify the code base, as we are no longer mucking with React internals. It might be possible to support a similar api as before, though it would remove a lot of these improvements.
Ylem will only have a future if it supports hooks. To that end, there are two decisions that need to be made regarding hook implementation.
## Providing the `Store`
The `Store` class must be provided to the hook in some manner. This can either be a 1 step process or a 2 step process:
### 1 step
The benefit here is simplicity: It is a single line.
```jsx
function Foo() {
const store = useYlemStore(Store);
return (
}
```
### 2 step
This separates the above line into two line. The first could be in the component, or it could be exported by the Store file itself (asa `import { useStore } from './store'`). In that case, the benefit is that all ylem-specific code is nowhere near the component; the component just gets data from a hook and doesn't need to know how it works.
```jsx
const useStore = createStoreHook(Store);
function Foo() {
const store = useStore();
return (
}
```
## Providing the Data
Data will need to be provided to ylem, for initializing and updating the store; this will most likely come from `props`. For simplicity, I will assume option 2 above.
### props
I propose that the primary method is for the hook to take props. In lieu of other configuration, the props would be used for initializing the store and changes to props will be diffed and those patches will be applied to the store.
```jsx
function Foo(props) {
const store = useStore(props);
return (
}
```
As is the standard with `useEffect` and other hooks, we should accept a second argument that is used for validating if the store needs to be updated. This can simply be proxied to the underlying `useEffect` call, so it should require very little work on our end.
```jsx
function Foo(props) {
const store = useStore(props, [ props.name ]);
return (
}
```
### Function
I propose that the same hook can also take a function. This function would be called with the current store instance. This function can do some combination of three things:
1. Modify the store instance. `const store = useStore((store) => { store.name = props.name; })`
2. Return a plain object, which will be diffed and patched as if that object were passed directly (see above section). `const store = useStore(() => ({ data: props }))`
3. Return a promise that resolves to a plain object, it will behave as the object does above. This option will allow us to tie into react's upcoming suspense feature.
## Additional Pieces
### Observing without creating a store
Whether or not this is exposed to user-land, there will be a hook which just handles the observing/rerendering. This takes no data and returns no data. Is there a use case for exposing this?
```jsx
function Foo() {
useYlem();
return (
}
```
### Model Provider
Many react projects make use of providers, allow some piece of information to be defined at a level higher than it is consumed. One possibility in our case is to have a `ModelProvider`.
It would look something like this, allowing one to use a string in place of a store constructor. This would work with either method of providing the store constructor.
```jsx
function Foo() {
return (
);
}
function Bar() {
const store = useYlemStore('MyStore');
return (
}
```
```jsx
function Bar() {
const Store = useModel('MyStore');
// do something with Store
return (
}
```
Contributor guide
Research direction
No files, tests, or entry points are named. Start by reviewing the proposed hook APIs for Store provision, prop or function data updates, observation, and ModelProvider behavior; the issue is complete only after those design decisions are resolved and an implementation scope is agreed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100