8 ms·
How to write PureScript react components to replace JavaScript
- andrenth 6y agoNot to hijack the thread, but I’ve recently learned that Purescript-Native has a Go target [1]. Does anyone have experience with this? How practical would it be to use this where one would otherwise use Go? [1] https://discourse.purescript.org/t/purescript-native-can-now-target-golang/878 https://discourse.purescript.org/t/purescript-native-can-now...
- chvid 6y agoThis is the corresponding code written in React using hooks: export const Counter = ({label, counterType, onClick}) => { const [counter, setCounter] = useState(0); return ( <button onClick={() => { counterType == "Increment" && setCounter(counter + 1); counterType == "Decrement" && setCounter(counter - 1); onClick && onClick(); }}> {label}: {counter} </button> ); } I think the case for PureScript React would be more convincing if the code you ended up with was loosely as concise as the above.
- kalyantm 6y agoExactly my thought. I've always loved FP, I write JS in a FP style at work, and have always wanted to get into learning something like Elm/PureScript (and eventually Haskell) but I feel like it takes ages to get productive. That PureScript React example alone has me thinking twice. But as a general question, what would be a better way to approach these languages?
- bgorman 6y agoConsider looking at ReasonML and ReasonReact, you can write stringly typed code at first, later you can start relying on type inference and ADTs
- omniscient_oce 6y agoYeah, ReasonML and ReasonReact are great because you're still writing JSX and not some over-engineered voodoo rewrite of React and/or JS but you get the power of strong types and ADTs and a super fast compiler.
- quickthrower2 6y agoThat is why I like Typescript as an option. Protect me from my dumb mistakes with types, but let me be fast and loose like JS.
- k_bx 6y agoElm shouldn't take more than a week to be productive if you know other existing language. I ran a study group where people spent few hours a week, the group took 7 meetings to finishing the book and discussing a variety of possible problems to solve with Elm. It's a much simpler language than PureScript.
- rhlsthrm 6y agoCan you explain more about writing JS in an FP style? I'd love to start to incorporate more FP in my JS but I don't really know how to start doing that. I've looked at fp-ts but it seems like that would require a full rewrite. Any tips for how to basically start from 0 and start to implement FP into an existing JS/TS codebase?
- pocket_titan 6y agoI'd suggest just learning and applying fp principles in JS incrementally. You'll feel a bit constrained at first (in part b/c JS allows you to do many "dirty" things), but you'll end up writing better code. Try to rely on 1) pure functions/no side-effects: a functions return value should be completely determined by its input 2) immutability: no Array.push, pop, or any method that modifies its input values 3) recursion instead of for & while loops. You'll probably feel the need for stronger typing at some point when adhering to these principles, and that's when I'd suggest looking at Typescript. By trying the things above you'll likely get familiar with the issues TS is trying to solve & you'll appreciate it more. Note that fp-ts is just a "helper" library for functional concepts, but it won't teach you their value or how to use them. Also: many libraries have fp variations! Next time you reach for lodash, try lodash/fp instead: it has the same tools you'll already be familiar with, but implemented in a functional manner.
- hombre_fatal 6y agoI think FP UI solutions don't necessarily win the 10-liner demo (except for representing client state with an AGDT), but your app also isn't a 10-liner. FP approaches to UI like Elm win the 100+ line comparisons for reasons you can't see, like minimizing runtime errors and making it so that impossible states are impossible at the type level. Unfortunately it's hard to see the benefits until you get your hands dirty. I use Elm in production on some apps and its a good place to start if you want simplicity. Personally, Purescript never interested me because I don't like all the complexity of more advanced Haskell features. While Elm specifically avoids certain advanced features to stay simple. You might like it given your concerns.
- evanrelf 6y agoThe snippets in the article are not using React with hooks. I imagine it would be more similar to your example if the snippets used purescript-react-basic-hooks[1] [1]: https://github.com/spicydonuts/purescript-react-basic-hooks https://github.com/spicydonuts/purescript-react-basic-hooks
- Cthulhu_ 6y agoNo, they're using more 'old fashioned' class-based components with state; function-based components using hooks is the modern way of writing React. Less boilerplate, for one.
- tbenst 6y agoIt’s not react, but author of this post also developed a hooks library for Purescript Halogen: https://github.com/thomashoneyman/purescript-halogen-hooks https://github.com/thomashoneyman/purescript-halogen-hooks
- crooked-v 6y agoAlso, you can get compile-time strict typing in Typescript with some minor annotations added to that: export const Counter: FunctionComponent<{ label: string; counterType: 'Increment' | 'Decrement'; onClick: () => void }> = ({ label, counterType, onClick }) => { const [counter, setCounter] = useState<number>(0); return ( <button onClick={() => { counterType == "Increment" && setCounter(counter + 1); counterType == "Decrement" && setCounter(counter - 1); onClick && onClick(); }}> {label}: {counter} </button> ); }
- chvid 6y agoYes. You can add types if you want. And maybe one can discuss if there is a more elegant syntax than the C-style syntax of JavaScript (there is ...). Other than that. I think the code is about as concise as it gets.
- ddek 6y agoThere is a change I’d make though - I’d memo-ise the click handler with useCallback. By using the function ‘overload’ on setState, which is guaranteed not to change, the callback will only be calculated (?) when the onclick handler changes. The setState would look like this: setState(c => c + 1);. Right now, the callback is interpreted on every render cycle.
- Cthulhu_ 6y agoPedantic and what always happens when someone posts code on the internet, but, I'd extract the onClick function and provide a default value for the onclick parameter for readability, and use cleverness to show off: export const Counter = ({label, counterType, onClick}) => { const [counter, setCounter] = useState(0); onClick = onClick || () => {}; const handleClick = () => { const modifier = counterType === "Increment" ? 1 : -1; setCounter(counter + modifier); onClick(); } return ( <button onClick={handleClick}> {label}: {counter} </button> ); } There's another commenter that uses Typescript, but I believe PropTypes (https://www.npmjs.com/package/prop-types https://www.npmjs.com/package/prop-types) are still viable as well - although it moves the checking from compile-time to runtime. I do believe VS Code and co can interpret PropTypes to provide in-editor hints though. And JSDoc as well.
- Softcadbury 6y agoYou should also use useCallback for handleClick
- johnrackles 6y agoCan you explain why? I don't think I've ever used useCallback and certainly not for this type of functionality. I'd love to learn
- neolefty 6y agouseCallback memoizes (caches) the function definition. Its main use is to simplify refreshes — since the function isn't redefined every time, components that depend on it such as the <button> can be re-rendered less often. const handleClick = useCallback(() => { const modifier = counterType === "Increment" ? 1 : -1 setCounter(counter + modifier) onClick() }, [onClick, counter, counterType, modifier]) The array at the end is the list of "dependencies" — whenever one of them changes, the function is re-cached. Compiler checks can catch missing dependencies. You might think, "But that function will be redefined pretty much every time," and in this case that's true, and memoization may not help much. But in bigger trees of components, most redraws will be unrelated to any given element, so those dependencies will rarely change. useCallback() (and its twin useMemo(), for non-functional values) gets more useful in deeper component trees, where values may be passed down several levels.
- noelwelsh 6y agoFWIW here's a Purescript example from the `purescript-react-basic-hooks` homepage[1]. It's not 100% identical but it is fairly close. mkCounter :: Effect (ReactComponent {}) mkCounter = do component "Counter" \props -> React.do counter /\ setCounter <- useState 0 pure $ R.button { onClick: handler_ do setCounter (_ + 1) , children: [ R.text $ "Increment: " <> show counter ] } Your aesthetic / background may differ from mine, but I find the Purescript version easier to read. [1]: https://github.com/spicydonuts/purescript-react-basic-hooks https://github.com/spicydonuts/purescript-react-basic-hooks
- diggan 6y agoNot sure I misunderstand the code that you're posting, but seems to not have the whole increment vs decrements parts in it, which would be interesting to see.
- TexInWien 6y agoThe following line defines a function (the syntax is known as an 'operator section'): (_ + 1) Equivalent to this JS function: x => x + 1 Operator Sections: https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md#operator-sections https://github.com/purescript/documentation/blob/master/lang...
- rkangel 6y agoI think the parent's point is that it only includes increment and not decrement.
- noelwelsh 6y agoYou are correct, which is why I said "[I]t's not 100% identical". Although I can read Purescript reasonably well I'm not so proficient writing it (I do most of my programming in a different FP language, so I understand the concepts but not the specifics.) I didn't attempt to modify the code I pulled from the example because it would take more time than I have to install Purescript and check my modifications. It would be simple to add this functionality. This equivalent of the `counterType` would be an algebraic data type, defined looking something like data counterType = Increment | Decrement and usage something like case counterType of Increment -> ... make increment here ... Decrement -> ... make decrement here ...
- diggan 6y agoDid someone say concise? Here is a ClojureScript + Reagent example for whoever is interested in that: (defn Counter [{:keys [label counterType onClick] :or {onClick (fn [])}}] (let [count (r/atom 0)] [:button {:onClick #(do (swap! count (condp = counterType :increment inc :decrement dec)) (onClick))} (str label ": " @count)])))
- edjroot 6y agoAwesome! Would you mind talking some more about your experience with it? I just got started with Clojure and Fulcro[1] (a full-stack framework) and I'm really, really excited about the possibilities. Have you heard about it? Here are some features off the top of my head (at least that's what they claim): - Well-integrated stack, so very little friction - “Datomic on the front end”: Client-side time-traveling database with automatic normalization, querying via EQL (kinda like GraphQL but more idiomatic and supposedly more powerful), “co-locating” queries in the UI. - React bindings and a Semantic UI library - Lets you swap anything you “outgrow” - Lots of learning material (but still lacking in some areas from a cursory look). The author seems to be very active on Slack (Clojurians #fulcro). - Fulcro RAD[2] (currently alpha) looks like it's going to reduce friction even further. There's probably more cool stuff I don't remember now. The two things I'm still insecure about with Clojure are its dynamically typed nature (but I'd be glad to hear about how that isn't a problem) and that the ecosystem doesn't seem to hold your hand too much (again, I'd like to hear another point of view). [1] https://fulcro.fulcrologic.com/benefits.html https://fulcro.fulcrologic.com/benefits.html [2] https://github.com/fulcrologic/fulcro-rad https://github.com/fulcrologic/fulcro-rad
- slifin 6y agoI'm making this same journey (I'm on video 5), and I'm making some notes for each video in Roam and teaching/learning each video every week via Google Meet on Bristol's Clojure Meetup I recommend using clj-kondo to catch the kinds of silly mistakes a type system is usually good for, yesterday we discovered that the react component interop is really good, we decided to try using https://chakra-ui.com/ https://chakra-ui.com/ over semantic ui and it's really straight forward to use React components that have no awareness of Fulcro or CLJS I think in terms of hand holding Fulcro does a really good job once you get into the weeds because it has an opinion and documentation for many problems, if you want to join us we're #bristol-clojurians on slack
- jrh206 6y agoPosting code on the internet - dangerous business! I think the counter updates should use functional updates, since they depend on the current state. My understanding is that this can lead to a potential race condition, although I'm not 100% on the details. setCounter(currentCounter => currentCounter + 1) https://reactjs.org/docs/hooks-reference.html#functional-updates https://reactjs.org/docs/hooks-reference.html#functional-upd... Interestingly your code is similar to some the first code in the basic 'into to hooks' section of the docs. Perhaps it's not a huge issue? Maybe somebody else who knows a bit more about React internals can chime in.
- chvid 6y agoThe code I wrote is perfectly fine. There is no possibility of race conditions in the code I wrote.
- deleted 6y ago[deleted]
- evanrelf 6y agoYou can also use React Hooks in PureScript with purescript-react-basic-hooks[1]. Or for a more native PureScript approach to single-page web apps, check out purescript-halogen[2] and purescript-halogen-hooks[3] (created by the author of this article). [1]: https://github.com/spicydonuts/purescript-react-basic-hooks https://github.com/spicydonuts/purescript-react-basic-hooks [2]: https://github.com/purescript-halogen/purescript-halogen https://github.com/purescript-halogen/purescript-halogen [3]: https://github.com/thomashoneyman/purescript-halogen-hooks https://github.com/thomashoneyman/purescript-halogen-hooks
- quickthrower2 6y agoIs PureScript nice to use again? Tried it a year or two ago and it relied heavily on Bower and I had a hard time getting anything to work on Windows - lots of Bower errors and such. I tried it a few years ago and got it to work, but in that case getting Halogen to compile the most basic app just stuck the compiler into a freeze for minutes, so I gave up. But I am not shitting on PureScript, it looks like a fantastic way to develop JS apps, and I'd love to use it.
- jamil7 6y agoI'm also wondering the same thing, after the whole Elm meltdown I've been looking for something similar to learn on the side.
- tannhaeuser 6y agoElm meltdown?
- goldenkey 6y agohttps://news.ycombinator.com/item?id=22821447 https://news.ycombinator.com/item?id=22821447
- nsonha 6y agoI hate to be that guy but I expected this from the begining. When you make a language that can only does one thing (web programming) it's destined to go into obscurity. All maintream languages are multiple-purposes. Even javascript is, thesedays.
- quickthrower2 6y agoI'm not in the market myself at the moment, but I would consider Fable (F#) for that job.
- quickthrower2 6y agoSorry that was a brain fart nonseq
- Osiris 6y agoThe article says that PureScript helped them reduce bugs but fails to give any examples of how PureScript prevented bugs. Looking at the examples, the code seems to function the same so it's not obvious what problem is being solved that warrants teaching a whole dev team a new language. In my experience, the vast majority of React app bugs are 1) state management, or 2) asynchronousisty. How does PureScript help to prevent those two classes of bugs?
- roebk 6y agoIn my experience the vast majority of React bugs are standard bugs you'd find in any JavaScript program, null reference errors. PureScript will force you to handle nulls as a Maybe, preventing a whole class of bugs.
- edem 6y agoWhy would anyone write purescript when we have typescript?
- nsonha 6y agoAs a gateway to haskell?
- azangru 6y agoWould you write client-side web apps in Haskell?
- shirogane86x 6y agoI mean, there are people who do, using GHCJS and something like Miso or Reflex.
- jamil7 6y agoWhy write in any other language when we have typescript? /s There is a world outside the JS/TS/Node ecosystem, pick up some of these other languages and it will answer your question.
- rkangel 6y agoI would phrase the question as "why would you write Typescript when we have Purescript (or ReasonML)"? Why would you choose to write a language who's type system is much less expressive than languages like Purescript? Why not have that expressive power and its ability to prevent some classes of bugs, and still have good interop with JS?
- e12e 6y agoI was actually thinking, why would you use purescript for react, when you could use reasonml? https://reasonml.github.io/reason-react/docs/en/components https://reasonml.github.io/reason-react/docs/en/components https://reasonml.github.io/reason-react/docs/en/usestate-event-value https://reasonml.github.io/reason-react/docs/en/usestate-eve... As far as I can tell the integration is cleaner and has better support from upstream? I guess it's not Haskell - but I really would be interested in why you would choose purescript for this use-case (personal preference is a fine reason, but I'd at least hope that preference goes beyond merely syntax?).
- lightgreen 6y ago> JavaScript apps to PureScript > Both companies have seen a dramatic drop in bugs in production. I suspect if they migrated from JavaScript to TypeScript instead they would have seen the same dramatic drop in bugs, but also migrated much quicker and would be able to hire engineers easier, and development speed would have increased (because of much better tooling/IDE/interop). I think PureScript is a very bright project, I even want to try it myself, but realistically, comparison to plain JavaScript is not the best benchmark.
- michaelcampbell 6y agoI admire his CLI approach to things, but this just seems dogmatic: echo -e "\noutput\n.psc*\n.purs*\.spago" >> .gitignore Sure, ok, saying "add these entries to your .gitignore" is too pedestrian?
- e12e 6y agoAt least I'd prefer a simple here-doc: tee -a .gitignore <<'EOF' output .psc* .purs* .spago EOF (or use: cat <<'EOF' >> .gitignore output .psc* .purs* .spago EOF But I think the tee-version more readily emphasize what's going on, and works with sudo).
- oweqruiowe 6y agoHow do they connect child components to parts of the application state in PureScript? I'm looking for a mechanism like react-redux's `connect` function. Something that eliminates the need to pass state through the root component down to everything else.
- azangru 6y agoHow is Purescript these days? I haven't heard many news from its ecosystem since Phil Freeman stepped down from its active development. Purescript by Example must be quite outdated by now? I know that Alex Kelley is still working on his set of tutorials "Make the Leap from Javascript to Purescript"[0]. Anything else interesting going on? I feel like there was a lot of excitement about Purescript in around 2015-2016, but then it sort of died out? 0 - https://github.com/adkelley/javascript-to-purescript https://github.com/adkelley/javascript-to-purescript
- scns 6y agoThe book is being kept up to date by the community: https://github.com/purescript-contrib/purescript-book https://github.com/purescript-contrib/purescript-book
- TexInWien 6y agoThere's plenty of interesting activity going on: The Discourse ( https://discourse.purescript.org/ https://discourse.purescript.org/ ) and Slack channels ( https://fpchat-invite.herokuapp.com/ https://fpchat-invite.herokuapp.com/ ) are active (and quite welcoming / helpful). A community fork of "PureScript by Example" is being updated / maintained, here: https://book.purescript.org/ https://book.purescript.org/ Try PureScript is back online after a hiatus: https://try.purescript.org/ https://try.purescript.org/ The compiler is now at version 0.13.8 with reasonably regular updates (and 0.14.0 should be on the way reasonably soon): https://github.com/purescript/purescript/releases https://github.com/purescript/purescript/releases Spago, the new(ish) package manager, is quite nice: https://github.com/purescript/spago https://github.com/purescript/spago The VSCode integration is solid. I'd say the tooling story is pretty good, over all. Work is underway to provide a package registry, since bower is being phased out: https://github.com/purescript/registry https://github.com/purescript/registry Halogen 5 was released recently: https://github.com/purescript-halogen/purescript-halogen https://github.com/purescript-halogen/purescript-halogen
- BFatts 6y agoDo we need another strongly typed language that compiles to JavaScript? If that's so important, why don't people use C/C++ and compile that to WASM for best performance too? We've got TypeScript... is it necessary to have yet another language??
- jamil7 6y agoPurescript is from a different family and has different goals. Overall though more languages and more choice is a good thing. Typescript (I'm thankful it's around) is just the path of least resistance and has therefore become the defacto.
- fristys 6y agoHoly shit that syntax looks disgusting. No way Jose.
- barbarbar 6y agoIt seems like a horrible idea to introduce this one off framework where ever you go. I feel sorry for the companies that has to carry the burden of the rewrite to something known. This should be used for a hobby at home.