{"id":13881057,"url":"https://github.com/jamesknelson/govern","last_synced_at":"2025-04-07T18:12:11.687Z","repository":{"id":57252659,"uuid":"91965528","full_name":"jamesknelson/govern","owner":"jamesknelson","description":"Component-based state management for JavaScript.","archived":false,"fork":false,"pushed_at":"2018-09-26T02:40:39.000Z","size":702,"stargazers_count":265,"open_issues_count":0,"forks_count":6,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-03T04:37:46.764Z","etag":null,"topics":["controllers","react","state","state-management"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesknelson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-21T15:00:01.000Z","updated_at":"2024-12-30T16:38:06.000Z","dependencies_parsed_at":"2022-08-31T22:20:49.427Z","dependency_job_id":null,"html_url":"https://github.com/jamesknelson/govern","commit_stats":null,"previous_names":[],"tags_count":76,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Fgovern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Fgovern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Fgovern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Fgovern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesknelson","download_url":"https://codeload.github.com/jamesknelson/govern/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247704571,"owners_count":20982298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["controllers","react","state","state-management"],"created_at":"2024-08-06T08:03:55.029Z","updated_at":"2025-04-07T18:12:11.644Z","avatar_url":"https://github.com/jamesknelson.png","language":"TypeScript","readme":"Govern\n======\n\nA component-based state management library.\n\n[![npm version](https://img.shields.io/npm/v/govern.svg)](https://www.npmjs.com/package/govern)\n\n[Try it live at CodeSandbox](https://codesandbox.io/s/31oo429ql1).\n\n---\n\nManaging state in React apps can be daunting. Govern makes it straightforward.\n\nWith Govern, you manage your state with an API you already know - *components*. Govern components are just like React components - they receive props, call `setState`, and define lifecycle methods. But where React components render UI elements, Govern components render plain old JavaScript objects.\n\nGovern components can handle state, actions, side effects, and selectors. This means that Govern can replace redux (or MobX), redux-thunk, redux-saga, reselect, and even recompose. But you can still use these tools when it makes sense - Govern is flexible, just like React.\n\nAnd if you know React, then you already know most of Govern's API, so you'll be productive in no time.\n\n```bash\n# Install with NPM\nnpm install --save govern react-govern\n\n# Install with Yarn\nyarn add govern react-govern\n```\n\nSimple, Sensible Forms: A Guide.\n--------------------------------\n\nCreating forms with React can be a little awkward. While React components are great for representing the form's UI, most forms also have a lot of business logic behind the UI.\n\nGovern makes forms simpler by allowing you to write components that *just* manage business logic.\n\nThis guide will walk you through creating a Govern component that manages the business logic for user registration, including:\n\n- Form state\n- Validation\n- Submitting a request\n- Redirecting the user on success\n\n\n### Defining Govern components\n\nGovern components are just JavaScript classes that extend `Govern.Component`. Like React components, they have `props`, `state`, and lifecycle methods like `componentDidMount` and `componentDidUpdate`.\n\nTo build a form, you'll need to store the form's state somewhere. And ideally, this state will be decoupled from the view -- which makes a Govern component the perfect place to store it!\n\nForms are usually composed from multiple fields. So let's start by building a component that models a single field's logic. It'll need to output the following:\n\n- The current value of the field\n- A function to change the current value\n- Any validation errors\n\nHere's an example of how you could make this component with Govern:\n\n```js\nimport * as Govern from 'govern'\n\nclass FieldModel extends Govern.Component {\n  static defaultProps = {\n    defaultValue: ''\n  }\n\n  constructor(props) {\n    super(props)\n\n    this.state = {\n      value: props.defaultValue,\n    }\n  }\n\n  render() {\n    let value = this.state.value\n    let error = this.props.validate ? this.props.validate(value) : null\n\n    return {\n      value: this.state.value,\n      error: error,\n      change: this.change,\n    }\n  }\n\n  change = (newValue) =\u003e {\n    this.setState({\n      value: newValue,\n    })\n  }\n}\n```\n\nThe neat thing about the above component is that if you know React, you already know what is going on here!\n\nThe only difference from a standard React component is that instead of rendering UI elements, you render raw data. Which you can then subscribe from within your view.\n\n\n### Subscribing to a Govern component\n\nGovern provides a `\u003cSubscribe to\u003e` React component that allows React components to subscribe to Govern components.\n\nThis component takes a Govern element for its `to` prop, and a render function for its `children` prop. It calls the render function with each new published value -- kind of like a super-powered version of React's context API.\n\nHere's a barebones example that connects a `\u003cFieldModel\u003e` to an input field. [See it live at CodeSandbox](https://codesandbox.io/s/0y10o4977l).\n\n```js\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\nimport { Subscribe } from 'react-govern'\n\nReactDOM.render(\n  \u003cSubscribe to={\n    // JSX is optional. This is equivalent to:\n    // Govern.createElement(Model, { validate: validateEmail })\n    \u003cFieldModel validate={validateEmail} /\u003e\n  }\u003e\n    {emailModel =\u003e\n      \u003clabel\u003e\n        Email: \n        \u003cinput\n          value={emailModel.value}\n          onChange={e =\u003e emailModel.change(e.target.value)}\n        /\u003e\n        {\n          emailModel.error \u0026\u0026\n          \u003cp style={{color: 'red'}}\u003e{emailModel.error}\u003c/p\u003e\n        }\n      \u003c/label\u003e\n    }\n  \u003c/Subscribe\u003e,\n  document.getElementById('root')\n)\n\nfunction validateEmail(value) {\n  if (value.indexOf('@') === -1) {\n    return \"please enter a valid e-mail\"\n  }\n}\n```\n\nOf course, forms usually have a number of fields, and it would be downright tedious to hook them all up this way. In fact, if you've used React Context, you may have experienced this yourself. Luckily, Govern gives you another option.\n\n### Combining components\n\nGovern components can render more than just plain old JavaScript objects -- like React, they can also render other components!\n\n```js\nclass WrapperComponent extends Govern.Component {\n  render() {\n    return (\n      \u003cFieldModel\n        validate={validateEmail}\n        defaultValue={this.props.defaultValue.email}\n      /\u003e\n    )\n  }\n}\n```\n\nThere's just one problem -- how do you combine multiple components? Unlike React, Govern isn't rendering to the DOM, so you can't wrap multiple components with `\u003cdiv\u003e` or `\u003cspan\u003e` tags.\n\nTo solve this, Govern provides its own primitives for combining elements. For example, the `Govern.combine` primitive can be used to render an object with the latest values of some specified elements:\n\n```js\nclass RegistrationFormModel extends Govern.Component {\n  static defaultProps = {\n    defaultValue: { name: '', email: '' }\n  }\n\n  render() {\n    let defaultValue = this.props.defaultValue\n\n    return Govern.combine({\n      name:\n        \u003cFieldModel\n          defaultValue={defaultValue.name}\n          validate={validateNotEmpty}\n        /\u003e,\n      email:\n        \u003cFieldModel\n          defaultValue={defaultValue.email}\n          validate={validateEmail}\n        /\u003e,\n    })\n  }\n}\n\nfunction validateNotEmpty(value) {\n  if (!value) {\n    return \"please enter your name\"\n  }\n}\n```\n\nAnd with that, you now have a component that manages the state of your entire form! You can then subscribe to the form model with `\u003cSubscribe to\u003e`, just as before.\n\nOne of the benefits of using the same `\u003cFieldModel\u003e` component for every field is that it makes creating reusable form controls simpler. For example, you could create a `\u003cField\u003e` React component to render your field models. [See it live at CodeSandbox](https://codesandbox.io/s/vv09or2853).\n\n```js\nclass Field extends React.Component {\n  render() {\n    return (\n      \u003clabel style={{display: 'block'}}\u003e\n        \u003cspan\u003e{this.props.label}\u003c/span\u003e\n        \u003cinput\n          value={this.props.model.value}\n          onChange={this.handleChange}\n        /\u003e\n        {\n          this.props.model.error \u0026\u0026\n          \u003cp style={{color: 'red'}}\u003e{this.props.model.error}\u003c/p\u003e\n        }\n      \u003c/label\u003e\n    )\n  }\n\n  handleChange = (e) =\u003e {\n    this.props.model.change(e.target.value)\n  }\n}\n\nReactDOM.render(\n  \u003cSubscribe to={\u003cRegistrationFormModel /\u003e}\u003e\n    {model =\u003e\n      \u003cdiv\u003e\n        \u003cField label='Name' model={model.name} /\u003e\n        \u003cField label='E-mail' model={model.email} /\u003e\n      \u003c/div\u003e\n    }\n  \u003c/Subscribe\u003e,\n  document.getElementById('root')\n)\n```\n\n\n### Stateless functional components\n\nLike React, Govern allows you to define your components as simple render functions.\n\nFor example, you could convert the above `\u003cRegistrationFormModel\u003e` component to a stateless functional component. [See it live at CodeSandbox](https://codesandbox.io/s/n5993ozp5l).\n\n```js\nconst RegistrationFormModel = ({ defaultValue }) =\u003e\n  Govern.combine({\n    name: \u003cFieldModel defaultValue={defaultValue.name} validate={validateNotEmpty} /\u003e,\n    email: \u003cFieldModel defaultValue={defaultValue.email} validate={validateEmail} /\u003e\n  });\n\nRegistrationFormModel.defaultProps = {\n  defaultValue: { name: '', email: '' } \n}\n```\n\n\n### Submitting forms\n\nOnce you have some data in your form, submitting it is easy -- you just publish a `submit` handler along with the form data. Everything you know about handling HTTP requests in React components transfers over to Govern components.\n\nBut before we can make a request, we need to know data the request should contain. Which is a problem, because the form data is stored within a child component...\n\n#### The `value` instance variable\n\nEach Govern component has a `value` instance variable that holds the current rendered value. You can use this to access the actions and state that child components have exposed to subscribers.\n\nFor example, a `RegistrationFormController` component could render a `\u003cRegistrationFormModel\u003e`, and use the `value` instance variable to get the form's state when the user presses \"submit\":\n\n```js\nclass RegistrationFormController extends Govern.Component {\n  render() {\n    return Govern.combine({\n      model: \u003cRegistrationFormModel /\u003e,\n      submit: this.submit,\n      request:\n        this.state.action \u0026\u0026\n        \u003cPostRegistrationRequest\n          data={this.state.action.data}\n\n          // Like React, components will be unmounted and remounted if the key\n          // changes. This ensures that resubmitting results in a new request.\n          key={this.state.action.key}\n        /\u003e,\n    })\n  }\n\n  submit = e =\u003e {\n    e.preventDefault();\n\n    let data = {\n      email: this.value.model.email.value,\n      name: this.value.model.name.value\n    };\n\n    // Make an AJAX request with the form's data.\n    postRegistration(data)\n  };\n}\n```\n\n\n#### Request components\n\nOne great thing about Govern is that it let's you re-use patterns that are already well understood by the community. For example, you could implement your request by following Dave Ceddia's excellent guide on [AJAX Requests in React](https://daveceddia.com/ajax-requests-in-react/).\n\nOf course, the other great thing about Govern is that it let's you decouple your UI from your state -- without learning a brand new API. One practical example is that you can put your AJAX logic in *Request Components*. Like with Dave Ceddia's guide, these components make a request on mount. But instead of rendering the output directly to the UI, they render an object containing the request's status.\n\n```js\nimport * as axios from \"axios\";\n\nclass PostRegistrationRequest extends Govern.Component {\n  state = {\n    isBusy: true,\n  }\n\n  render() {\n    return this.state\n  }\n\n  componentDidMount() {\n    axios.post('/user', this.props.data)\n      .then(response =\u003e {\n        if (!this.isCancelled) {\n          this.setState({\n            data: response.data,\n            isBusy: false,\n            response,\n            wasSuccessful: true,\n          })\n        }\n      })\n      .catch(response =\u003e {\n        if (!this.isCancelled) {\n          this.setState({\n            data: response \u0026\u0026 response.data,\n            isBusy: false,\n            response,\n            wasError: true,\n          })\n        }\n      });\n  }\n\n  componentWillUnmount() {\n    // If the component is unmounted, we should not handle the response.\n    this.isCancelled = true\n  }\n}\n```\n\nDefining requests as Govern components may feel a little weird at first, but it has some big advantages:\n\n- Requests can automatically retry on failure, outputting a relevant status as they change\n- Unlike promises, request components can output progress and be cancelled by unmounting\n- You can pass elements around as \"lazy\" requests - they won't be run until they're mounted\n\nRequest components also make it easy to share communication logic within and between applications. For an example, see [this gist](https://gist.github.com/jamesknelson/ab93890eb26f2841a2f8846d4013b151) of an axios-based `\u003cRequest\u003e` component.\n\nOnce you have a request component like `PostRegistrationRequest`, you can start it by subscribing to it from a parent component. [See it live at CodeSandbox](https://codesandbox.io/s/313j167zpp).\n\n```js\nclass RegistrationFormController extends Govern.Component {\n  state = {\n    action: null\n  };\n\n  render() {\n    return Govern.combine({\n      model: \u003cRegistrationFormModel /\u003e,\n      submit: this.submit,\n      request:\n        this.state.action \u0026\u0026\n        \u003cPostRegistrationRequest\n          data={this.state.action.data}\n\n          // Like React, components will be unmounted and remounted if the key\n          // changes. This ensures that resubmitting results in a new request.\n          key={this.state.action.key}\n        /\u003e,\n    })\n  }\n\n  submit = e =\u003e {\n    e.preventDefault();\n    this.setState({\n      action: {\n        data: {\n          email: this.value.model.email.value,\n          name: this.value.model.name.value\n        },\n        key: Date.now(),\n      }\n    });\n  };\n}\n\nReactDOM.render(\n  \u003cSubscribe to={\n    \u003cRegistrationFormController /\u003e\n  }\u003e\n    {({ model, request, submit }) =\u003e (\n      \u003cform onSubmit={submit}\u003e\n        {request \u0026\u0026\n          request.wasError \u0026\u0026 (\n            \u003cp style={{ color: \"red\" }}\u003eYour request failed :-(\u003c/p\u003e\n          )}\n        \u003cField label=\"Name\" model={model.name} /\u003e\n        \u003cField label=\"E-mail\" model={model.email} /\u003e\n        \u003cbutton type=\"submit\"\u003e\n          Register\n        \u003c/button\u003e\n      \u003c/form\u003e\n    )}\n  \u003c/Subscribe\u003e,\n  document.getElementById(\"root\")\n);\n```\n\nNote how the `key` prop is used in the above example; just like React, changing `key` will result in a new component instance being created, and thus a new request being made each time the user clicks \"save\".\n\nBut while we do want the user to be able to start a new request if the previous one failed, we don't want the user to accidentally start two requests, or to start a second request after the first one succeeds. How can we keep track of this?\n\n\n### Computed values\n\nSuppose that the `RegistrationFormController` component renders a `canSubmit` boolean. This would make it possible to guard against resubmission by checking `this.value.canSubmit` within the `submit` action, and to set the `disabled` prop of the submit button.\n\nThis hypothetical `canSubmit` value would be `true` when:\n\n- The model does not have any errors, and\n- Submit hasn't been clicked yet (i.e. `this.state.action` is null) or\n- The previous submit failed (i.e. `this.value.request.wasError` is true)\n\nWhile `this.value` can't be accessed directly from within `render()`, Govern provides a `map` primitive that allows you to map the output of an element, just like you can map an array.\n\nFor example, you could use `Govern.map` to compute a `canSubmit` value for the above component as so. [See it live at CodeSandbox](https://codesandbox.io/s/l7pk9wnpjl).\n\n```js\nclass RegistrationFormController extends Govern.Component {\n  state = {\n    action: null\n  };\n\n  render() {\n    return Govern.map(\n      Govern.combine({\n        model: \u003cRegistrationFormModel /\u003e,\n        request:\n          this.state.action \u0026\u0026\n          \u003cPostRegistrationRequest\n            data={this.state.action.data}\n            key={this.state.action.key}\n          /\u003e,\n      }),\n      ({ model, request }) =\u003e ({\n        model,\n        request,\n        submit: this.submit,\n        canSubmit:\n          !model.email.error \u0026\u0026 !model.name.error \u0026\u0026\n          (!request || request.wasError)\n      })\n    )\n  }\n\n  submit = e =\u003e {\n    e.preventDefault();\n    if (this.value.canSubmit) {\n      this.setState({\n        action: {\n          data: {\n            email: this.value.model.email.value,\n            name: this.value.model.name.value\n          },\n          key: Date.now(),\n        }\n      });\n    }\n  };\n}\n```\n\nGovern's `map` and `flatMap` primitives serve a similar purpose to the React [Render Prop](https://reactjs.org/docs/render-props.html) pattern. However, map/flatMap have a number of advantages:\n\n- You can use `shouldComponentUpdate` (doing so in React components with render props results in weeping and gnashing of teeth)\n- You can change the structure of components' children (doing so in React results in child components being remounted)\n- You can use the `combine` primitive on mapped components (combining React components with render props results in pyramids of doom)\n\nBut returning to our registration form example, the user now has a problem - once they've registered, they'll be stuck on a screen with a disabled form. Let's fix this by automatically redirecting them to a welcome page.\n\n\n### Reacting to changes in value\n\nTo redirect away from the page when the request completes, we just need to watch for the `wasSuccessful` value of `\u003cPostRegistrationRequest\u003e` to turn to true.\n\nGovern doesn't currently provide a way to watch a controller's output value. But not to worry, we can just pass the output through another component's props using the `flatMap` primitive, and watch it that way.\n\n[See it live at CodeSandbox](https://codesandbox.io/s/31oo429ql1).\n\n```js\nclass RegistrationFormController extends Govern.Component {\n  state = {\n    action: null\n  };\n\n  render() {\n    return Govern.flatMap(\n      Govern.combine({\n        model: \u003cRegistrationFormModel /\u003e,\n        request:\n          this.state.action \u0026\u0026\n          \u003cPostRegistrationRequest\n            data={this.state.action.data}\n            key={this.state.action.key}\n          /\u003e,\n      }),\n      ({ model, request }) =\u003e \n        \u003cInnerRegistrationFormController\n          // Separate the output (which will be passed through to our\n          // subscribers) from the props used by the inner component itself.\n          history={this.props.history}\n          output={{\n            model,\n            request,\n            submit: this.submit,\n            canSubmit: \n              !model.email.error \u0026\u0026 !model.name.error \u0026\u0026\n              (!request || request.wasError)\n          }}\n        /\u003e\n    )\n  }\n\n  submit = e =\u003e {\n    e.preventDefault();\n    if (this.value.canSubmit) {\n      this.setState({\n        action: {\n          data: {\n            email: this.value.model.email.value,\n            name: this.value.model.name.value\n          },\n          key: Date.now(),\n        }\n      });\n    }\n  };\n}\n\nclass InnerRegistrationFormController extends Govern.Component {\n  hasNavigated = false\n\n  render() {\n    return this.props.output\n  }\n\n  componentDidUpdate() {\n    let request = this.props.output.request\n    if (request \u0026\u0026 request.wasSuccessful \u0026\u0026 !this.hasNavigated) {\n      this.hasNavigated = true\n      this.props.history.push('/members/welcome')\n    }\n  }\n}\n```\n\nSo what's the difference between `map` and `flatMap`? Simple:\n\n- `map` expects a function that **returns a plain JavaScript object**\n- `flatMap` expects a function that **returns an element**\n\n\nThe App Observable\n------------------\n\nMost apps have a single \"App\" component that holds application-wide state, including authentication, cached data, etc. Because this component is relevant to the entire app, mounting it with the react-govern \u003cSubscribe\u003e doesn't make sense -- it would cause the entire app to be re-rendered on any change, and would require you to pass the output via props or React context.\n\nIt's best to stick to `\u003cSubscribe\u003e` where possible. But when you need more control, you can create a **Govern observable**.\n\nGovern observables are wrappers around a Govern component. They can be manually instantiated, and passed to primitives like `map` and `flatMap` in place of elements. You can also pass them through React props and context, allowing you to access app-level state within controllers for individual screens.\n\n\n### An offline indicator\n\nThis example App observable exports a value that indicates whether the user is online or offline. A React component then subscribes to the offline indicator using `flatMap` and `distinct` -- which ensures that the indicator only re-renders when `isOnline` changes, regardless of other changes within the store.\n\nThe App also exports an automatically increasing `counter` variable; notice how even though the counter is increasing, the online/offline status only changes when you enable/disabled your network connectivity.\n\n[See it live at CodeSandbox](https://codesandbox.io/s/9yzkqx9wr).\n\n```js\nimport * as Govern from \"govern\";\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport { Subscribe } from \"react-govern\";\n\nclass App extends Govern.Component {\n  state = {\n    isOnline: window.navigator.onLine,\n    counter: 1\n  };\n\n  render() {\n    return this.state;\n  }\n\n  componentDidMount() {\n    window.addEventListener(\"offline\", this.handleOnlineChange);\n    window.addEventListener(\"online\", this.handleOnlineChange);\n    window.setInterval(() =\u003e {\n      this.setState(state =\u003e ({\n        counter: state.counter + 1\n      }));\n    }, 1000);\n  }\n\n  handleOnlineChange = () =\u003e {\n    this.setState({\n      isOnline: window.navigator.onLine\n    });\n  };\n}\n\nconst appObservable = Govern.createObservable(\u003cApp /\u003e);\n\nlet counterRenderCount = 0;\nlet networkRenderCount = 0;\n\nReactDOM.render(\n  \u003cdiv\u003e\n    \u003cSubscribe\n      to={Govern.flatMap(appObservable, app =\u003e Govern.distinct(app.counter))}\n    \u003e\n      {counter =\u003e (\n        \u003cReact.Fragment\u003e\n          \u003ch3\u003eCounter (rendered {++counterRenderCount} times)\u003c/h3\u003e\n          {String(counter)}\n        \u003c/React.Fragment\u003e\n      )}\n    \u003c/Subscribe\u003e\n    \n    \u003cSubscribe\n      to={Govern.flatMap(appObservable, app =\u003e Govern.distinct(app.isOnline))}\n    \u003e\n      {isOnline =\u003e (\n        \u003cReact.Fragment\u003e\n          \u003ch3\u003eNetwork status (rendered {++networkRenderCount} times)\u003c/h3\u003e\n          {isOnline ? \"ONLINE\" : \"offline\"}\n        \u003c/React.Fragment\u003e\n      )}\n    \u003c/Subscribe\u003e\n  \u003c/div\u003e,\n  document.getElementById(\"root\")\n);\n```\n\n\n\nTwo out of Three types of state\n-------------------------------\n\nReact application state can be split into roughly three categories:\n\n-   App store\n\n    State that is global to your entire application. For example:\n\n    * Navigation state\n    * Communication state\n    * Authentication state\n    * Cached data\n\n    *Govern is great at handling environment state, and can also be integrated with your existing Redux or MobX-based store.*\n\n-   Controllers\n\n    State that represents that current view, and any actions that have been initialized from it. For example:\n\n    * Form state\n    * Errors form requests\n    * Selected list items\n\n    *Govern is great at handling control state.*\n\n-   View state\n\n    State that represents the view, but does not affect the environment or control state. For example, animations, transitions, and state for controlling interactions with DOM elements.\n\n    *Govern is **not** meant to handle view state. Use React component state instead.*\n\n\nAPI Documentation\n-----------------\n\n### Govern.Component\n\nGovern components are JavaScript classes that extend `Govern.Component`, and contain a `render()` method.\n\nIf you've used React, the component API will be familiar. There are just a few differences:\n\n- `render` can output anything!\n- There are no refs; use `this.value` instead\n- Context is not supported; use Govern Observables instead\n- `getSnapshotBeforeUpdate` is not available (or necessary)\n- The `dispatch` method allows for manually specified batches\n\n##### Rendering\n\n- `render()`\n- `value` (the latest output of the element returned by `render()`)\n\n##### Methods shared with React\n\n- `constructor()`\n- `static getDerivedStateFromProps()`\n- `componentWillReceiveProps()`\n- `componentDidMount()`\n- `componentDidUpdate()`\n- `componentWillUnmount()`\n- `setState()`\n\n##### Miscellaneous methods\n\n- `dispatch()`\n\n##### Instance properties shared with React\n\n- `props`\n- `state`\n\n##### Class properties shared with React\n\n- `defaultProps`\n\n---\n\n#### Component Lifecycle\n\n##### `constructor()`\n\n```js\nconstructor(props)\n```\n\nSimilar to React's component [constructor](https://reactjs.org/docs/react-component.html#constructor), a Govern component's constructor can be used to bind event handlers, set initial state, etc.\n\n##### `static getDerivedStateFromProps()`\n\n```js\nstatic getDerivedStateFromProps(props, state)\n```\n\nSimilar to React's [getDerivedStateFromProps](https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops), this can be used to compute state from props.\n\n##### `componentDidMount()`\n\n```js\ncomponentDidMount()\n```\n\nSimilar to React's [componentDidMount](https://reactjs.org/docs/react-component.html#componentdidmount), this component will be called once the initial output is available.\n\nNote that this will be called *before* the initial value of the component is flushed to any listening `\u003cSubscribe\u003e` components.\n\nAny Govern state changes caused by this method will be executed before changes are flushed to React.\n\n##### `componentWillReceiveProps()`\n\n```js\ncomponentWillReceiveProps(nextProps)\n```\n\nSimilar to React's [UNSAFE_componentWillReceiveProps](https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops). Not prefixed with `UNSAFE_` as Govern doesn't have plans for supporting async rendering.\n\nWhere possible, avoid this in favor of `static getDerivedStateFromProps`.\n\n##### `shouldComponentUpdate()`\n\n```js\nshouldComponentUpdate(nextProps, nextState)\n```\n\nSimilar to React's [shouldComponentUpdate](https://reactjs.org/docs/react-component.html#shouldcomponentupdate).\n\nWhen defined, returning a falsy value will prevent `render` from being called.\n\n##### `componentDidUpdate()`\n\n```js\ncomponentDidUpdate(prevProps, prevState)\n```\n\nSimilar to React's [componentDidUpdate](https://reactjs.org/docs/react-component.html#componentdidupdate), but receives a third argument with the previous `value`.\n\nAny Govern state changes caused by this method will be executed before changes are flushed to `\u003cSubscribe\u003e` React components.\n\n##### `componentWillUnmount()`\n\n```js\ncomponentWillUnmount()\n```\n\nSimilar to React's [componentWillUnmount](https://reactjs.org/docs/react-component.html#componentwillunmount) lifecycle method, this component will be called before a component is scheduled to be disposed.\n\n##### `setState()`\n\n```js\nsetState(updater[, callback])\n```\n\nSimilar to React's [setState](https://reactjs.org/docs/react-component.html#setstate).\n\n##### `dispatch()`\n\n```js\ndispatch(actionFunction)\n```\n\nThe dispatch method allows you to ensure that a group of changes only result in a single flush to your React app via `\u003cSubscribe\u003e` components.\n\nThis method is never required, but can be used to improve performance when making multiple changes in response to a single event.\n\n\n#### Instance properties\n\n##### `props`\n\nIdentical to React's [`props`](https://reactjs.org/docs/react-component.html#props).\n\n##### `state`\n\nIdentical to React's [`state`](https://reactjs.org/docs/react-component.html#state).\n\n##### `value`\n\nThis property holds the latest output of the element that was returned from your component's `render()` method.\n\n\n#### Class properties\n\n##### `defaultProps`\n\nIdentical to React's [`defaultProps`](https://reactjs.org/docs/react-component.html#defaultprops).\n\n\n### Stateless functional components\n\nAs with React, you can define a component as a stateless function, which will be treated as the `render()` method of an otherwise empty component.\n\n```js\n// Stateless functional component\nconst SFC = () =\u003e\n  ({ foo: 'bar' })\n\n// Equivalent class component\nclass SFC extends Govern.Component {\n  render() {\n    return { foo: 'bar' }\n  }\n}\n```\n\n\n### Primitive Govern components\n\nGovern provides a number of primitives for composing elements. Typically these are accessed through the following factory methods:\n\n- `combine()`\n- `map()`\n- `flatMap()`\n- `distinct()`\n- `constant()`\n\nLike React, these can also be created by passing a string as the first argument to `Govern.createElement()`. Govern also accepts elements created by `React.createElement()`, so you can define them with JSX.\n\n#### `combine()`\n\n```js\n// With factory function\nGovern.combine({ name: elementOrObservable })\n\n// With JSX\n\u003ccombine\u003e{{\n  name: elementOrObservable\n}}\u003c/combine\u003e\n```\n\n#### `map()`\n\n```js\n// With factory function\nGovern.map(elementOrObservable, value =\u003e computedValue)\n\n// With JSX\n\u003cmap from={elementOrObservable} to={value =\u003e computedValue} /\u003e\n```\n\nMaps the output of `from`, using the function passed to `to`. Each publish on the `from` store will result in a new publish.\n\n#### `flatMap()`\n\n```js\n// With factory function\nGovern.flatMap(elementOrObservable, value =\u003e computedElement)\n\n// With JSX\n\u003cflatMap from={elementOrObservable} to={value =\u003e computedElement} /\u003e\n```\n\nMaps the output of `from`, using the output of whatever element is returned by `to`. Each published of the *mapped* element results in a new publish.\n\n#### `distinct()`\n\n```js\n// With factory function\nGovern.distinct(children, /* optional */ (x, y) =\u003e areValuesEqual)\n\n// With JSX\n\u003cdistinct by={/* optional */ (x, y) =\u003e areValuesEqual}\u003e\n  {elementOrObservable}\n\u003c/distinct\u003e\n```\n\nPublishes the output of the child element, but only when it differs from the previous output. By default, outputs are compared using shallow equality, but you can supply a custom comparison function via the `by` prop.\n\n#### `constant()`\n\n```js\n// With factory function\nGovern.constant(value)\n\n// With JSX\n\u003cconstant\u003e{{value}}\u003c/constant\u003e\n```\n\nAn element to represent an unchanging value. You won't usually need this, as objects returned from `render()` are treated as constants by default. However, it can come in handy in conjunction with `flatMap`, which expects its props to be elements.\n\n### React components\n\nThe *react-govern* package exports a single component for creating and subscribing to Govern stores/elements within React applications.\n\n#### `\u003cSubscribe\u003e`\n\n```js\n\u003cSubscribe to={elementOrObservable}\u003e\n  {value =\u003e \u003cSomeReactElement /\u003e}\n\u003c/Subscribe\u003e\n```\n\nMounts the given Govern Element (if necessary), and subscribes to it -- passing each value to the `children` render function.\n\nAny prop changes are passed through; if the type or key of the `to` element changes, the old component will be unmounted.\n\n\n### `GovernObservable` objects\n\nGovern components are basically observables. In fact, Govern lets you create Observables from Govern elements. These observables implement the proposed [ESNext Observable](https://github.com/tc39/proposal-observable) specification, along with some Govern-specific methods.\n\nObservables can be passed to `combine`, `flatMap` and `map`, in place of elements.\n\nGovern observables are a great way to manage an app-wide store. Just create an observable at the root of your application, then pass it down to where it is required using React context or as a prop, and subscribe to the parts you need with `distinct`, `map`, etc.\n\n#### `createObservable()`\n\n```\ncreateObservable(element)\n```\n\nInstantiates the component specified by the `element` argument, and returns a `GovernObservable` object that can be used to interact with the component.\n\n#### Observable methods\n\n##### `getValue()`\n\n```\nobservable.getValue()\n```\n\nReturn the component's current value.\n\n##### `subscribe()`\n\n```\nobservable.subscribe(onNext, onError?, onComplete?, onStartDispatch?, onEndDispatch?, priority?)\n```\n\n*In general, you should avoid manually creating subscriptions in favor of using the `\u003cSubscribe to\u003e` component from the *react-govern* package.*\n\nCreates a new subscription to the store.\n\nThis method is compatible with the proposed [ESNext Observable](https://github.com/tc39/proposal-observable) specification, and thus can be used with RxJS, etc.\n\nIf `onStartDispatch` and `onEndDispatch` are not provided, then `onNext` not be called during a dispatch. \n\n`Component.prototype.setState` cannot be called on the any component connected to the observable while `onNext` is being called. If you need to call actions during an `onNext` handler, wrap the call within `waitUntilNotFlushing()`.\n\n##### `dispose()`\n\n```\nobservable.dispose()\n```\n\nClean up any resources used by the observable.\n\n##### `waitUntilNotFlushing()`\n\n```\nwaitUntilNotFlushing(functionToRunWhenNotFlushing)\n```\n\nRuns the specified function once it is safe to call `setState` again. Mainly used when you need to call an action from within an observables `subscribe()` handler, or from within a React lifecycle method.\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesknelson%2Fgovern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesknelson%2Fgovern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesknelson%2Fgovern/lists"}