UNPKG

reason-react-brunch

Version:

React bindings for Reason, modified to work with brunch and bucklescript

151 lines (115 loc) 4.68 kB
--- title: Talk to Existing ReactJS Code --- ## Project Setup You can reuse the _same_ bsb setup (that you might have seen [here](installation.md#bsb))! Aka, put a `bsconfig.json` at the root of your ReactJS project: ```json { "name": "my-project-name", "reason": {"react-jsx" : 2}, "sources": [ "my_source_folder" ], "package-specs": [{ "module": "commonjs", "in-source": true }], "suffix": ".bs.js", "namespace": true, "bs-dependencies": [ "reason-react" ], "refmt": 3 } ``` This will build Reason files in `my_source_folder` (e.g. `reasonComponent.re`) and output the JS files (e.g. `reasonComponent.bs.js`) alongside them. Then add `bs-platform` to your package.json (`npm install --save-dev bs-platform` or `yarn add --dev bs-platform`): ```json "scripts": { "start": "bsb -make-world -w" }, "devDependencies": { "bs-platform": "^2.1.0" }, "dependencies": { "react": "^15.4.2", "react-dom": "^15.4.2", "reason-react": "^0.3.1" } ... ``` Running `npm start` (or alias it to your favorite command) starts the `bsb` build watcher. **You don't have to touch your existing JavaScript build configuration**! ## Usage A ReasonReact component **is not** a ReactJS component. We provide hooks to communicate between the two. Whether you're using an existing ReactJS component or providing a ReasonReact component for consumption on the JS side, you need to establish the type of the JS props you'd convert from/to, by using [BuckleScript's `bs.deriving abstract`](https://bucklescript.github.io/docs/en/object.html): ```reason [@bs.deriving abstract] type jsProps = { /* some example fields */ className: string, /* `type` is reserved in Reason. use `type_` and make it still compile to the JS key `type` */ [@bs.as "type"] type_: string, value: Js.nullable(int), }; ``` This will generate the getters and the JS object creation function (of the same name, `jsProps`) you'll need. **Note**: you do **not** declare `ref` and `key` (the two special ReactJS "props"). We handle that for you, just like ReactJS does. They're not really props. ### ReasonReact using ReactJS Easy! Since other Reason components only need you to expose a `make` function, fake one up: ```reason [@bs.module] external myJSReactClass: ReasonReact.reactClass = "./myJSReactClass"; let make = (~className, ~type_, ~value=?, children) => ReasonReact.wrapJsForReason( ~reactClass=myJSReactClass, ~props=jsProps( ~className, ~type_, ~value=Js.Nullable.fromOption(value), ), children, ); ``` `ReasonReact.wrapJsForReason` is the helper we expose for this purpose. It takes in: - The `reactClass` you want to wrap - The `props` js object you'd create through the generated `jsProps` function from the `jsProps` type you've declared above (with values **properly converted** from Reason data structures to JS) - The mandatory children you'd forward to the JS side. `props` is mandatory. If you don't have any to pass, pass `~props=Js.Obj.empty()` instead. **Note**: if your app successfully compiles, and you see the error "element type is invalid..." in your console, you might be hitting [this mistake](element-type-is-invalid.md). ### ReactJS Using ReasonReact Eeeeasy. We expose a helper for the other direction, `ReasonReact.wrapReasonForJs`: ```reason let component = ...; let make ...; [@bs.deriving abstract] type jsProps = { name: string, age: Js.nullable(int), }; let jsComponent = ReasonReact.wrapReasonForJs(~component, jsProps => make( ~name=jsProps |. name, ~age=?Js.Nullable.toOption(jsProps |. age), [||], ) ); ``` The function takes in: - The labeled reason `component` you've created - A function that, given the JS props, asks you to call `make` while passing in the correctly converted parameters (`bs.deriving abstract` above generates a field accessor for every record field you've declared). You'd assign the whole thing to the name `jsComponent`. The JS side can then import it: ``` var MyReasonComponent = require('./myReasonComponent.bs').jsComponent; // make sure you're passing the correct data types! <MyReasonComponent name="John" /> ``` **Note**: if you'd rather use a **default import** on the JS side, you can export such default from BuckleScript/ReasonReact: ```reason let default = ReasonReact.wrapReasonForJs(...) ``` and then import it on the JS side with: ``` import MyReasonComponent from './myReasonComponent.bs'; ``` BuckleScript default exports **only** works when the JS side uses ES6 import/exports. [More info here](https://bucklescript.github.io/docs/en/import-export.html#export-an-es6-default-value).