From 1db7c850cc4059fe97eb775b307046d0fec4e33e Mon Sep 17 00:00:00 2001 From: Vladimir Guguiev Date: Sun, 22 Jul 2018 11:31:10 +0200 Subject: [PATCH] fix review comments --- README.md | 64 ++++++++++++------------------- __tests__/RePureComponent-test.js | 2 +- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index afb5cb3..6d4cc63 100644 --- a/README.md +++ b/README.md @@ -368,56 +368,33 @@ If you‘re having troubles understanding this example, I recommend the fantasti _[Flow][] is a static type checker for JavaScript. This section is only relevant for you if you‘re using Flow in your application._ -ReComponent comes with first class Flow support built in. By default, a ReComponent will behave like a regular Component and will require props and state to be typed: +ReComponent comes with first class Flow support built in. +When extending `ReComponent`, in addition to the `Props` and `State` types required by regular `React.Component` +we need to specify the third generic parameter which should be a union of all actions used by the component. +This ensures type-safety everywhere in the code of the component where the actions are used and +even allows [exhaustiveness testing] to verify that every action is indeed handled. ```js import * as React from "react"; import { ReComponent, Update } from "react-recomponent"; type Props = {}; -type State = { count: number }; +type State = { count: number, value: string }; +type Action = {| type: "CLICK" |} | {| type: "UPDATE_VALUE", payload: string |}; -class UntypedActionTypes extends ReComponent { - handleClick = this.createSender("CLICK"); - state = { count: 0 }; - - static reducer(action, state) { - switch (action.type) { - case "CLICK": - return Update({ count: state.count + 1 }); - default: - return NoUpdate(); - } - } - - render() { - return ( - - ); - } -} -``` +class TypedActions extends ReComponent { + // NOTE: we use `this.send` API because it ensures type-safety for action's `payload` + handleClick = () => this.send({ type: "CLICK" }); + handleUpdateValue = (newValue: string) => this.send({ type: "UPDATE_VALUE", payload: newValue }); -Without specifying our action types any further, we will allow all `string` values. It is, however, recommended that we type all action types using a union of string literals. This will further tighten the type checks and will even allow [exhaustiveness testing] to verify that every action is indeed handled. - -```js -import * as React from "react"; -import { ReComponent, Update } from "react-recomponent"; - -type Props = {}; -type State = { count: number }; -type ActionTypes = "CLICK"; - -class TypedActionTypes extends ReComponent { - handleClick = this.createSender("CLICK"); state = { count: 0 }; static reducer(action, state) { switch (action.type) { case "CLICK": return Update({ count: state.count + 1 }); + case "UPDATE_VALUE": + return Update({ value: action.payload }); default: { return NoUpdate(); } @@ -426,9 +403,12 @@ class TypedActionTypes extends ReComponent { render() { return ( - + + + + ); } } @@ -438,7 +418,11 @@ Check out the [type definition tests](https://github.com/philipp-spiess/react-re **Known Limitations With Flow:** -- While it is possible to exhaustively type check the reducer, Flow will still require every branch to return an effect. This is why the above examples returns `NoUpdate()` even though the branch can never be reached. +- `this.send` API for sending actions is preferred over `this.createSender`. This is because `this.createSender` + effectively types the payload as `any` (limitation we can't overcome for now), whereas `this.send` provides full type-safety + for actions +- While it is possible to exhaustively type check the reducer, Flow will still require every branch to return an effect. + This is why the above examples returns `NoUpdate()` even though the branch can never be reached. ## API Reference diff --git a/__tests__/RePureComponent-test.js b/__tests__/RePureComponent-test.js index 5e68717..fdfd8f2 100644 --- a/__tests__/RePureComponent-test.js +++ b/__tests__/RePureComponent-test.js @@ -21,7 +21,7 @@ describe("RePureComponent", () => { class Example extends RePureComponent { constructor() { super(); - this.handleClick = () => this.send({ type: "CLICK" }); + this.handleClick = this.createSender("CLICK"); this.state = { count: 0 }; }