DEV Community

ReasonReact context explained in action

Margarita Krutikova on September 22, 2019

Context in react is designed for sharing some global data between components located at different levels of the component tree. It allows to avoid ...
Collapse
 
___zth___ profile image
zth

This is a great, thorough explanation, thanks a lot! I also found context in Reason very confusing at first. Thanks also for explaining why you can't use the normal React component annotation as well, that feels like a really important point.

Another trick, that's slightly more involved, is putting dispatch in a separate context, all by itself. That way you avoid having to pass a tuple (which I think will make all components using the context re-render as it creates a new array -> new context value each render) and components that only dispatch stuff don't need to re-render when state changes.

I guess more or less the same thing could be achieved with useMemo as well. Anyway, this probably only matters in a few use cases, but I thought it was worth mentioning as I've struggled with issues related to that myself.

I look forward to reading more articles from you!

Collapse
 
margaretkrutikova profile image
Margarita Krutikova

Thanks a lot for your comment!

You are totally right about memoization and having separate contexts for dispatch and actual value. It is a cool trick to avoid re-render of components that only need dispatch. Funny, I actually have those points as a comment in the source code, but I thought I would leave them out from the article 🙂

I think I will add them in the end, since it is important people are aware of them in case they encounter one of those "few cases". Thanks for mentioning this info! 👏

Collapse
 
idkjs profile image
Alain

You didn't use the hook in the app after all that?!?!?

For other's who might want to actually use it, example, here

Great write up, @margaretkrutikova . Nice details and teaching. Since you dug into makeProps, why do we have to call it with a unit arg? As in

let makeProps = (~value, ~children, ()){}

instead of which fails

let makeProps = (~value, ~children){}

Thanks again and keep it coming. Peace to you.

Collapse
 
margaretkrutikova profile image
Margarita Krutikova

Sorry, could you clarify what you mean by "you didn't use the hook in the app"? I did use it here.

That's actually a very good question. Usually you need to pass unit () in the end if you have optional labeled arguments. If you don't enforce this, the compiler won't know whether you want to partially apply arguments to your function (=curried function, and maybe pass that optional argument later?) or you actually want to omit that argument and call the function right away.

I assume, since all components can optionally receive key as prop, you have to explicitly pass that unit to make sure it is going to be called and not partially applied. You can see here in the docs that reason component will generate makeProps like this:

[@bs.obj]
external makeProps: (~name: 'name, ~key: string=?, unit) => {. "name": 'name} = "";

So I think it will always have that optional argument key. I hope this makes sense!

Collapse
 
idkjs profile image
Alain

Indeed you did. In your post you had it assigned to a function and looked for that in the code. You ended up using it directly in form onSubmit. github.com/MargaretKrutikova/pract...

Nice.

Optional key. Of course. I was wondering which of these props is optional. Tack, Madame. You are appreciated!

Collapse
 
hodatorabi profile image
hodatorabi

Great article. Just a little question. Are we actually initializing user two times? Once in root and once in the context?

Collapse
 
margaretkrutikova profile image
Margarita Krutikova

Thank you for your feedback!
That's a great question, I haven't really thought about it myself. It appears that the value passed inside context is a default value that will only be used if there is no matching Provider in the tree, just found it in the react docs. Could be useful for testing components in isolation.

I guess in the Javascript world one could simply omit passing a value in the context (resulting in undefined), here in Reason however we must pass a value of the correct type (context value). If it is important to not compute the initial value two times (due to some heavy things going on there), one could make it option and pass None in context and Some(computedValue) in the root.