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

useEffect, useContext, and other React utility apis. #3

Open
rebo opened this issue Jan 29, 2020 · 4 comments
Open

useEffect, useContext, and other React utility apis. #3

rebo opened this issue Jan 29, 2020 · 4 comments

Comments

@rebo
Copy link
Owner

rebo commented Jan 29, 2020

Other than use_state React has a number of other utility apis that make working with their Hooks much more productive.

I have implemented most of them in some form however I want to really pin down what to include in a useful Seed api.

Here are the most commonly used React ones are.

useRef - is basically what we have with use_state basically synchronous updating of state with no forced re-rendering.

useEffect - accepts a block that runs after the next render. This may be useful to programatically update certain items or trigger a re-render after a timeout. It ensures that your current component has been rendered.

useContext allows nested state within a nested components. i.e. component A has sub-views B and C. component A defines a context object, and component B and C has access to it via useContext.

useReducer creates a dispatch object that messages can be passed to. This then returns and updates the relevant state. This is as opposed to mutating state directly.

useCallback / useMemo Memoizes a value and only updates it if a dependency changes.

Of the above useMemo and useReducer would be most useful.

The use case for use_memo would be to cache an expensive value and only update it on request. For instance you could have a function that does a fetch request to update profile data:

let ready_bool.get()  = use_state(|| false);
let profile = use_memo( ready_bool.get(), || {
     fetch_profile_async(ready_bool)
});

div![profile]

This pattern would display a dummy profile until ready_bool.get() returns true in which case fetch_profile_async will update the memo with the loaded profile.

Another example where use_memo might be useful is when Seed evaluates every single view function which could include evaluation hundreds of divs![] and other node macros in a complex view. Using use_memo you would only need to evaluate this once and the Node tree can then be memoized. i.e.

use_memo(re_render, || {  ..lots and lots of divs and expensive node macros... } );

This doesn't save any view diffing but does save the cost of creating the virtual dom in the first place.

The case for use_reducer means that logic can be separated from the view somewhat. It is like a mini seed message-update-view cycle. i.e. the classic counter example would be something like:

enum ButtonMsg {
    Increment,
    Decrement,
}
fn reducer<T>(state: &mut T, msg:ButtonMsg){
    match msg {
      ButtonMsg::Increment => *state +=1,
      ButtonMsg::Decrement => *state -=1,
    }
}

fn my_button() -> Node<Msg> {
    let count = use_reducer(reducer, || 3);
    div![
        button![
            "-",
            mouse_ev(Ev::Click, move |_| {
                count.dispatch(ButtonMsg::Decrement);
                Msg::NoOp
            }),
        ],
        count.get().to_string(),
        button![
            "+",
            mouse_ev(Ev::Click, move |_| {
                count.dispatch(ButtonMsg::Increment);
                Msg::NoOp
            }),
        ],
    ]
}

This lets one keep TEA style on a per view function basis and is more suited if there is more complex logic needed than a single state value. The view function is still self contained as a component and can be used wherever.

@MartinKavik
Copy link
Contributor

MartinKavik commented Jan 29, 2020

useRef - we proved it's redundant.

useEffect - "accepts a block that runs after the next render" - we already have orders.on_next_render(|timestamp| ..) so maybe we can explore some simple alternatives for Seed. I can imagine it can be useful for animations.

useContext - "allows nested state within a nested components. i.e. component A has sub-views B and C. component A defines a context object, and component B and C has access to it via useContext." - it sounds pretty complicated and error-prone.

useReducer - I don't know if I like it. We wanted simple stateful components and boom, we have a stateful component with own React/Elm architecture and two message types. Imagine a question: "So... I want to write a component - should I write it in Seed/Elm architecture or React/Seed/Elm architecture or use Seed's use_state (which is basically React's use_ref) or write a Rust/Typescript WebComponent?" It would be tough question for experienced developer who knows Seed, React, Elm, Rust, Javascript, Typescript and WebComponents, beginners will run away.

useCallback / useMemo -

  • "cache an expensive value and only update it on request" - again, why do you want to do that in a simple component? I think that sending requests, error handling and expensive operations should be done only by the app core.
    • There are only two hard things in Computer Science: cache invalidation and naming things.

  • "This doesn't save any view diffing but does save the cost of creating the virtual dom in the first place. - Is Seed slow? I don't want to solve problems which don't exist. Once we decide to optimize it I would start in the core and modify public API when really needed.
    • Premature optimization is the root of all evil

@rebo
Copy link
Owner Author

rebo commented Jan 29, 2020

Yes all good points and keeping it simple is definitely a good strategy.

It's worth considering the above only in so far as they are part of React's core Hook api and some prior users of React may want to reach for them.

@MartinKavik
Copy link
Contributor

"It's worth considering the above only in so far as they are part of [X]'s core [Y] api and some prior users of [X] may want to reach for them."

  • where X is React, Vue, Elm, Svelte, Yew.. we have to define own API, the simplest one and yeah it's hard, especially when eveybody has different background :)
    and probably write more bigger examples for people coming from those framework, but it's a long-term goal

@rebo
Copy link
Owner Author

rebo commented Jan 29, 2020

agreed!

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

No branches or pull requests

2 participants