ReasonReact

ReasonReact

  • Docs
  • Try
  • Examples
  • Community
  • Blog
  • Languages iconEnglish
    • 日本語
    • Español
    • Français
    • 한국어
    • Português (Brasil)
    • Русский
    • 中文
    • 繁體中文
    • Help Translate
  • GitHub

›Recent Posts

Recent Posts

  • Support for the JSX transform under a new name `reason-react-ppx`
  • ReasonReact is back (and powered by Melange)
  • We are rebranding to ReScript / React
  • ReasonReact 0.9.0 - Uncurried and Code Cleanup
  • ReasonReact 0.8.0 🎉 BuckleScript Upgrade & More!

Support for the JSX transform under a new name `reason-react-ppx`

September 13, 2023

Today, we're releasing ReasonReact 0.12! The most important changes are renaming the JSX transform PPX from reactjs-jsx-ppx to reason-react-ppx, along with many other improvements:

  • reason-react-ppx now emits the React 17 JSX transform.
  • Prop locations have been greatly improved, resulting in much better editor integration.
  • Check the full changes below for more details around other fixes and small breaking changes.

Locations from domProps in action (Thanks @jchavarri)

download

new JSX transform (Thanks @anmonteiro)

Screenshot 2023-09-13 at 16 11 17

What's changing?

Track reactjs-jsx-ppx in the same repository as reason-react, and rename it to reason-react-ppx, a more suitable name with a few improvements:

  • Use the new JSX transform from React 17
  • Fix code-generation locations for JSX and props
  • Fix to allow using React.memoCustomCompareProps
  • Fix Type of optional prop not checked correctly in JSX
  • The ppx will be synced with reason-react (and tested together)

Take a look at reasonml/reason-react/releases/tag/0.12.0 for a full listing of all the changes.

Updating to latest

ReasonReact works best with Melange. Get started here.

Next:

  • Update the package definitions with opam update

  • Install the latest versions with opam install reason-react reason-react-ppx (or upgrade opam upgrade reason-react & install opam install reason-react-ppx)

  • In your dune file, add reason-react to libraries and reason-react-ppx to preprocess:

      (libraries reason-react)
      (preprocess (pps reason-react-ppx))
    
  • Remove any usage of ReactDOM.props

  • Bump React.js version to v17/v18 to use the new JSX transformation

  • We added depexts in opam for react and react-dom to ensure you have the correct versions installed from npm. depexts is the mechanism by opam to ensure the correct versions of external dependencies are present in your system. Learn more here on the Melange documentation page about bindings and package management:

      depexts: [
        ["react"] {npm-version = "^16.0.0 || ^17.0.0"}
        ["react-dom"] {npm-version = "^16.0.0 || ^17.0.0"}
      ]
    

Future plans

  • OCaml 5.1 + Melange v2
  • Reason 3.10 support
  • React 18 bindings
  • Continue improving the state of the ppx (locations, avoid raising, etc..)
  • Deprecate some legacy modules: ReasonReact and ReactDOMRe
  • Work on interface files

Feel free to reach out if you have any feedback or want to get involved. You can open an issue in this repository, or join the ReasonML Discord and contact me (@davesnx) directly.

ReasonReact is back (and powered by Melange)

June 11, 2023

ReasonReact moved to @rescript/react after the ReScript announcement. The future of ReasonReact has been uncertain ever since. In the meantime, the Melange team announced the first major release of Melange and took the first steps towards deeper integration with the OCaml ecosystem.

Today, we are happy to announce that ReasonReact is back and will be maintained by the Melange team going forward.

What's changing?

We released ReasonReact to the opam repository. In the Melange docs, we document how to depend on packages in opam.

We updated the documentation to reflect these new changes and we will continue to improve it over time.

Adopting ReasonReact

To use ReasonReact, you must be using Melange. Get started here.

Next:

  • Install the latest version of ReasonReact: opam install reason-react
  • In your dune file, add reason-react to libraries and preprocess with reactjs-jsx-ppx:

(libraries reason-react) (preprocess (pps react-jsx-ppx))

  • Replace any previously deprecated modules with their new names: ReactDOMRe -> ReactDOM, ReactEventRe -> ReactEvent, ReasonReact -> React.
  • Remove any usage of ReasonReactCompat and ReasonReactOptimizedCreateClass. These have long been deprecated, and have been removed in this version.

Future

We started moving all ReasonReact related packages to Melange and 0.11 and want to make sure the ReasonML community can update the 3rd party libraries to use Melange as well.

Some of them are published in github.com/melange-community or github.com/ahrefs. Examples include melange-react-dates or melange-recharts.

There's lots to do for the next version. We are committed to continue improving ReasonReact and make it a great library for the Melange and ReasonML community. In the future, we expect to make the following changes:

  • Track reacjs-jsx-ppx in this repository, and rename it to reason-react-ppx, a more suitable name
  • Use the new JSX transform from React 17
  • Fix code-generation locations for JSX and props
  • Continue improving the documentation

Feel free to reach out if you have any feedback. You can open an issue in this repository, or join the ReasonML Discord.

Full changelog

The version of ReasonReact published to npm is compatible with ReScript 0.9.0. Since then, we've fixed a few things:

  • [0.9.2] Add drag event API binding
  • [0.9.2] Add aria-haspopup as ariaHaspopup as prop
  • [0.9.2] Add aria-current as ariaCurrent as prop
  • [0.9.2] Add aria-checked as ariaChecked as prop
  • [0.10.0] Deprecate legacy modules (ReasonReact, ReasonReactCompat, ReasonReactOptimizedCreateClass)

Version 0.11

  • [0.11.0] Add suppressHydrationWarning
  • [0.11.0] Created opam package (reason-react.opam)
  • [0.11.0] Requires dune 3.8.0 (via dune-project)
  • [0.11.0] Full migration to Melange

Have a good day!

We are rebranding to ReScript / React

May 7, 2021

BuckleScript & Reason are now called ReScript, therefore the ReasonReact bindings will now be known as ReScript / React and need to be moved to a different npm package.

This means...

  • Our reason-react npm package will now be published as @rescript/react
  • rescript-react@0.10.1 is basically a cleaned up version of reason-react@0.9.1 (see the CHANGELOG for minor breaking changes).
  • The reason-react github repository will be archived. Please refer to our new repository at github.com/rescript-lang/rescript-react.
  • The next upcoming @rescript/react release will come with a few cool new features! Check out our RFC discussion for more infos.

Migration

From an API perspective, upgrading from reason-react to @rescript/react should be very easy, since most changes are a just matter of doing a few global search & replaces. Details for the changed APIs can be found in our revamped ReScript / React migration guide.

Important: All Libraries need to be upgraded to rescript/react

Unfortunately @rescript/react based projects are not compatible with libraries that depend on the old reason-react package due to dependency conflicts.

In other words: If you try to compile a project that uses both, @rescript/react and reason-react, the compiler will not compile due to a React module name collision.

There are currently three strategies to deal this issue:

  • As a temporary workaround, use a patching tool like npm patch-package to adjust the package dependencies of indidvidual bindings to @rescript/react (adapt package.json & bsconfig.json)
  • Ask the maintainer of your outdated third-party library to create a new major version release with @rescript/react as a dependency (don't forget to mention which version supports @rescript/react in the README).
  • Or as a third alternative, create an updated fork of the project, or copy the bindings directly in your ReScript project.
    • Also take the occasion to adapt bs- prefixed library names to our new ReScript package conventions. Otherwise your new libraries will not show up on our package index.

For more details on the name collision issue, please refer to this forum post.

We apologize for the inconvenience; we promise that the migration work will be worth it!

If you have any questions or migration issues, please open a discussion on the ReScript Forum to get support, or ping @ryyppy / @rickyvetter on Github.

Thanks for being part of the ReasonReact community and see you on the ReScript side!

ReasonReact 0.9.0 - Uncurried and Code Cleanup

June 8, 2020

Release 0.9.0 is primarily to setup for larger changes in coming BuckleScript and ReasonReact release, but that's not all that's there. Exciting new features include React.Uncurried hooks which provide even cleaner JS output and better performance for hooks that get called in hot loops. Additionally we now have better support for Strict mode, ErrorBoundaries, and pointer events.

There are two breaking changes which most people are unlikely to hit:

  1. We have stopped versioning lib/js and will not ship on NPM. If you are using this library from Reason you will be unaffected. If you're using directly from handwritten JS, you could run into issues. If you want to continue doing this, you can include the code you're using into a Reason file in your codebase where you have more control over how it is exposed.
  2. We have changed the APIs of some of the ReactDOM.Experimental namespace. As the namespace implies, this code is not intended for production app use and you likely will not notice any difference here.

Take a look at https://github.com/reasonml/reason-react/blob/main/HISTORY.md#090-052020 for a full listing of all the changes and credit to the incredible folks who have contributed.

ReasonReact 0.8.0 🎉 BuckleScript Upgrade & More!

May 5, 2020

We're excited to share Version 0.8.0 of ReasonReact with the world today! ReasonReact adds a huge number of quality of life improvements and new api changes. This is our first big release since introducing hooks in 0.7.0.

It's a breaking change primarily because it enforces a minimum BuckleScript version of 7.1.1. This is to ensure that we get consistent record and object runtime representation and to unlock more changes in the future. Going forward you can expect that ReasonReact will track BuckleScript more closely. The PPX lives in and ships with BuckleScript, so in order to make sweeping changes we have to work in both codebases.

There are a number of additional breaking changes:

  • crossOrigin casing was incorrect
  • maxDuration removed from suspense api
  • Ref type has been changed to be modelled as a record instead of abstract type with get and set
  • The min attribute on dom nodes in now a string to match max

As well as new additions:

  • Support for concurrent mode with createRoot, Suspense, SuspenseList, useTransition
  • React.float and int
  • Better Children mapping

This is not an exhaustive list - I encourage you to check out the full set in https://github.com/reasonml/reason-react/blob/main/HISTORY.md.

This release has been a long time coming and is the huge effort of the ReasonReact community. A heartfelt thanks to everyone in the HISTORY and to everyone who has created or interacted with issues! The first step to upgrading here is to make sure you're on BuckleScript ^7.1.1. From there you can visit upgrade-reason-react for a script that will handle the ref upgrade, crossOrigin capitalization, and the type of min when used in JSX. Happy hacking!

New ReasonReact bsb template!

October 18, 2019

New examples

BuckleScript 6.2.1 just got released, and with it came a freshly updated bsb ReasonReact template. To try it, just use the official installation: bsb -init my-react-app -theme react-hooks.

If you like what ReasonReact's Router did to your routing experience, you'll love what this template does to your project scaffolding. Highlights:

  • No more development-time bundler needed!
    • Files are dynamically required every page reload. No caching, no stale bundle, no race condition. Bsb provided us some much needed sanity in the build system. We're now applying the same philosophy to the subsequent bundling step at development time.
    • Thanks to that, the entire edit-reload cycle is now in milliseconds, with cold reloading. No state bugs.
    • An optional, example bundler (Webpack) for production is provided, just for completeness.
  • This starter boilerplate now serves the extra purpose of being a ReasonReact examples repo.
    • Evergreen collection of use-cases right in your template. Supersedes the now-deprecated reason-react-examples repo.
    • Informative comments on possible, lean architecture choices. No decision paralysis.
    • Table of ReasonReact features used in the README, so that you can eye the ReasonReact API you need and directly jump into the corresponding file.
  • Finally, a front-end boilerplate you can 100% fit in your head!
    • Only two production dependencies: React and ReasonReact.
    • Only two development-time dependencies: BuckleScript and moduleserve (the latter resolves the requires during development).
    • Simple, transparent and great for learners. Nothing in the repo is opaque; everything can be tweaked. You get to make structural changes as you see fit.

Ever seen newcomers subconsciously blame themselves for not understanding a boilerplate when it's too rigid or fragile? It hurts to watch that. Front-end boilerplate generators have become complex beasts that have exceed the threshold acceptable for learning. For us, a boilerplate needs to enable folks to:

  • get to their first working screen quickly, and
  • understand the entirely of what's going on. Hard to change what you don't understand!

Most boilerplates overfit the first, at the huge expense of the second. There are simply too many layers of shaky abstractions piled on top of each other for a person to truly grasp it; all the bells and whistles one might think newcomers appreciate pale in comparison to the disempowerment they'd feel facing such large scope and fragile setups. It shouldn't feel this elaborate to put pixels on the screen!

Such boilerplate is no way to design learnability. That's why ours keeps things at a minimum, and should ironically feel much easier to get started with and to fully grasp than the opposite, overbearing approach. We encourage you to go through every file in the project; they're well-commented, succinct, and immediately useful. It goes without saying that we did not compromise on the polish of the examples =).

For a long time, folks thought their edit-reload experience would be achieved through adding more layers on top of their bundler; we believe, just like for our ReasonReact Router, that we've achieved this by removing the layers.

ReasonReact 0.7.0: Support for React Hooks

April 10, 2019

Version 0.7.0 of ReasonReact adds support for the React Hooks API. This allows for writing function components with state and complex interactions.

You can now write components like

[@react.component]
let make = (~className, ~text) => <div className> {text} </div>;

which will compile to a 0-cost React component that looks like

let make = ({className, text}) => <div className={className}> {text} </div>;

In these new components you can make use of the full Hooks api:

type action =
  | Tick;

type state = {
  count: int,
};

[@react.component]
let make = () => {
  let (state, dispatch) = React.useReducer(
    (state, action) =>
      switch (action) {
      | Tick => {count: state.count + 1}
      },
    {count: 0}
  );

  React.useEffect0(() => {
    let timerId = Js.Global.setInterval(() => dispatch(Tick), 1000);
    Some(() => Js.Global.clearInterval(timerId))
  });
  
  <div>{ReasonReact.string(string_of_int(state.count))}</div>;
};

Please read the new documentation for an in-depth explanation of how to write these components and how they compile to existing ReactJS code.

These components make use of a new jsx implementation that desugars exactly to React.createElement calls. In order to use these new components with JSX you will need to use [@bs.config {jsx: 3}] at the top of your file and use ^5.0.4 or ^6.0.1 BuckleScript which supports this new version. If you are in a greenfield project or you have fully converted, you can also change the JSX version in your bsconfig.json file to 3 and drop the in-file annotations.

This release also makes use of a new React namespace for APIs for all of the code related to this new way of writing components. Some functions have been copied over (like React.string, React.array) and many are new (like hooks)!

The only breaking change for this API is the introduction of new namespaces, which should be a fairly straightforward fix that most people won't need to do. However, since lots of the new code won't work without a more recent version of BuckleScript, we do recommend doing an upgrade on this version first and treating this as a breaking change even if you have no React namespace conflict. If you're interested in migrating some components the upgrade script is provided. It will wrap existing ReasonReact components as if they are Hooks components. This script will not attempt to re-write your logic as hooks because this is often a complicated process and it is not guaranteed to be correct. Please always inspect and test the work of the migration script to make sure it does what you're expecting!

ReasonReact 0.6.0 (Small Release)

March 12, 2019

Hello! It's been a while. We've been heads down working on a few secret features these days; in the meantime, hopefully you enjoyed the stability of the API so far.

We're making a tiny release today to improve some nits. Consider this blog post as a heart beat. Don't forget to come to Reason Conf! We have some ReasonReact stuff to share with you there.

As usual, release notes are here. No migration script this time; it's just a single letter change.

ReasonReact 0.5: Fragment, Event, Cleanups

August 6, 2018

It's been a while since the last blog post! Note that we've been updating ReasonReact, just that we didn't want to drown you with too many blog posts when unnecessary. As we've said in our ReasonConf video, we wanted the ReasonReact community to catch up and settle down a bit before showering it with another batch of changes.

As usual, the proper list of changes are in HISTORY.md, likewise for the migration script. Major highlights:

  • Fragment support.
  • ReactEventRe -> ReactEvent revamp.
  • General cleanups that removes a bunch of already deprecated features.

There are also many other quality-of-life improvements that, combined together, should reduce the arbitrary newcomer frictions in some places.

See you next time!

Router and Subscriptions!

January 9, 2018

Happy new year! We've got a new, non-breaking release for you =). As always, here's the migration script and here's the list of changes.

V0.3.1 brings two important features, both super lightweight and performant, yet strike, we hope, a sweet spot in terms of usability:

  • Router! It's tiny and has almost no learning overhead.
  • Subscriptions helper. Helps you cut down on some boilerplate.

These two features follow our spirit of keeping the learning and performance overhead low, while providing facilities that codifies your existing knowledge of ReactJS. In particular, note how:

  • The subscriptions helper prevents you from forgetting to free your event listeners and timers.
  • The router just uses pattern-matching to kill a majority of otherwise needed API surface.

There are no FAQs for these two features. Check out the linked docs; you can use your existing understanding of Reason to answer your questions: is this performant? Will this work in my existing setup? How does nesting work? Etc. Special thanks to Ryan Florence and Michael Jackson for some small conversations.

Additionally, we've deprecated self.reduce in favor of self.send (the migration script takes care of that):

  • Before: onClick={self.reduce(_event => Click)}

  • After: onClick={_event => self.send(Click)}

  • Before: didMount: self => {self.reduce(() => Click, ()); NoUpdate}

  • After: didMount: self => {self.send(Click); NoUpdate}

This change should drastically reduce the confusion of an immediately called self.reduce (the form with two arguments). It also rolls on the tongue better: you "send" an action to the reducer.

Happy coding!

Next →