{"id":13400729,"url":"https://github.com/Wildhoney/Keo","last_synced_at":"2025-03-14T06:31:54.536Z","repository":{"id":1769066,"uuid":"44556469","full_name":"Wildhoney/Keo","owner":"Wildhoney","description":"Plain functions for a more functional Deku approach to creating stateless React components, with functional goodies such as compose, memoize, etc... for free.","archived":false,"fork":false,"pushed_at":"2023-01-24T22:39:42.000Z","size":10430,"stargazers_count":227,"open_issues_count":17,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-18T21:59:07.586Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://keo-app.herokuapp.com/","language":"JavaScript","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/Wildhoney.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-19T18:53:06.000Z","updated_at":"2023-07-23T05:48:11.000Z","dependencies_parsed_at":"2023-02-14T02:15:48.487Z","dependency_job_id":null,"html_url":"https://github.com/Wildhoney/Keo","commit_stats":null,"previous_names":[],"tags_count":96,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wildhoney%2FKeo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wildhoney%2FKeo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wildhoney%2FKeo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wildhoney%2FKeo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Wildhoney","download_url":"https://codeload.github.com/Wildhoney/Keo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243537895,"owners_count":20307098,"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":[],"created_at":"2024-07-30T19:00:54.961Z","updated_at":"2025-03-14T06:31:54.531Z","avatar_url":"https://github.com/Wildhoney.png","language":"JavaScript","funding_links":[],"categories":["Uncategorized","MVC Frameworks and Libraries","JavaScript","MVC Frameworks and Libraries [🔝](#readme)","Libraries and Frameworks","Marks","MVC 框架和库","React [🔝](#readme)"],"sub_categories":["Uncategorized","Runner","ReactJS","[React - A JavaScript library for building user interfaces](http://facebook.github.io/react)","运行器","运行器e2e测试"],"readme":"\u003cimg src=\"media/logo.png\" alt=\"Keo\" width=\"250\" /\u003e\n\n\u003e \u003csub\u003e\u003csup\u003e*[\"Keo\"](https://vi.wikipedia.org/wiki/Keo) is the Vietnamese translation for glue.*\u003c/sup\u003e\u003c/sub\u003e\u003cbr /\u003e\n\u003e Plain functions for a more functional [Deku](https://github.com/dekujs/deku) approach to creating stateless React components, with functional goodies such as compose, memoize, etc... for free.\n\n![Travis](http://img.shields.io/travis/Wildhoney/Keo.svg?style=flat-square)\n\u0026nbsp;\n![npm](http://img.shields.io/npm/v/keo.svg?style=flat-square)\n\u0026nbsp;\n![License MIT](http://img.shields.io/badge/License-MIT-lightgrey.svg?style=flat-square)\n\n* **npm:** `npm install keo --save`\n\n\u003cimg src=\"media/screenshot.png\" /\u003e\n\n---\n\n## Table of Contents\n\n* [Advantages](#advantages)\n* [Getting Started](#getting-started)\n* [Destructuring](#destructuring)\n* [Shadow DOM](docs/SHADOW_DOM.md)\n* [Nonstandard Properties](#nonstandard-properties)\n* [Testing Smart Components](#testing-smart-components)\n\nAt the core of Keo's philosophies is the notion that you **shouldn't** have to deal with the `this` keyword \u0026mdash; and while in ES2015 the `this` keyword has become easier to manage, it seems wholly unnecessary in a React component. As such, Keo takes a more [Deku](https://github.com/dekujs/deku) approach in that items such as `props`, `context`, `nextProps`, etc... are passed in to [*some*](#lifecycle-functions) React [lifecycle functions](https://facebook.github.io/react/docs/component-specs.html).\n\nSince `v4.x`, Keo has taken on a more fundamental interpretation of React where components are **expected** to be passed immutable properties \u0026mdash; and `state` is entirely inaccessible, as is `setState` to prevent components from holding their own state. As such, you are **required** to use Redux with Keo to pass properties down through your components.\n\n\u003e **Note:** Prior to `v4.x` Keo had a different API which was more tolerant \u0026mdash; please use `npm i keo@3.0.2` \u0026mdash; [See associated README](LEGACY.md)\n\n## Advantages\n\n* Steer away from `class` sugaring, inheritance, and `super` calls;\n* Create referentially transparent, pure functions without `this`;\n* Gain `memoize`, `compose`, et cetera... for gratis with previous;\n* Use `export` to export plain functions for simpler unit-testing;\n* Simple composing of functions for [*mixin* support](https://github.com/dekujs/deku/issues/174);\n* Avoid functions being littered with React specific method calls;\n* Integrated `shouldComponentUpdate` performing immutable equality checks from `propTypes`;\n* An assumption that [immutable properties](http://www.sitepoint.com/immutability-javascript/) are used for performance gains;\n* Use `render` composition to enable [Shadow DOM](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/) support in React;\n\n## Getting Started\n\nUse [Redux](https://github.com/reactjs/redux) to pass down properties through your components, and an immutable solution \u0026mdash; such as [`seamless-immutable`](https://github.com/rtfeldman/seamless-immutable) or Facebook's [`Immutable`](https://facebook.github.io/immutable-js/) \u0026mdash; even [`Object.freeze`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) can in many cases be perfectly acceptable for getting started.\n\nOnce you're setup with Redux, and your project is passing down immutable properties, within your first component you can import `stitch` from Keo. In the following example we'll assume the immutable property `name` is being passed down to your component:\n\n```javascript\nimport React from 'react';\nimport { stitch } from 'keo';\n\nconst render = ({ props }) =\u003e {\n    return \u003ch1\u003e{props.name}\u003c/h1\u003e\n};\n\nexport stitch({ render });\n```\n\nIn the above example the component will re-render **every time** properties are updated in your Redux state \u0026mdash; even when the `name` property hasn't been changed. React provides the [`PureRenderMixin` mixin](https://facebook.github.io/react/docs/pure-render-mixin.html) for these instances, and Keo provides a similar solution based on `propTypes`.\n\nTaking advantage of the `shouldComponentUpdate` improvement means you **must** define your `propTypes` \u0026mdash; Keo favours this approach over checking `props` directly to encourage strictness in component definitions. It's also important to remember that you should enumerate props that are passed to your child components \u0026mdash; see React's documentation [Advanced Performance](https://facebook.github.io/react/docs/advanced-performance.html).\n\n```javascript\nimport React, { PropTypes } from 'react';\nimport { stitch } from 'keo';\n\nconst propTypes = {\n    name: PropTypes.string.isRequired\n};\n\nconst render = ({ props }) =\u003e {\n    return \u003ch1\u003e{props.name}\u003c/h1\u003e\n};\n\nexport stitch({ propTypes, render });\n```\n\nWith the above component definition **only** when the `name` property has changed will the component re-render \u0026mdash; in many cases this provides a [huge performance gain](https://facebook.github.io/react/docs/advanced-performance.html). It's important to benchmark your React applications using tools such as [`react-addons-perf`](https://facebook.github.io/react/docs/perf.html) \u0026mdash; and in particular the `printWasted` function which will demonstrate the benefit of using `shouldComponentUpdate`.\n\n## Destructuring\n\nIn keeping with one of Keo's philosophies that the `this` keyword should be avoided \u0026ndash; Keo provides a way to destructure required arguments from within your components:\n\n```javascript\nconst componentDidMount = ({ props }) =\u003e {\n    dispatch(fetch(`/user/${props.user.id}`));\n};\n```\n\nProperties which can be destructured are as follows:\n\n* `props` which are passed down via Redux;\n* `dispatch` which is an alias for `props.dispatch`;\n* `context` allowing access to such modules as `router`;\n\nProperties which are typically available in React components, but are unavailable in Keo components:\n\n* `state` and `setState` as stateless components are forbidden to maintain local state;\n* `refs` use `event.target` on events instead;\n* `forceUpdate` as components are only updated via `props`;\n\n## Lifecycle Functions\n\nThe entire gamut of [React's lifecycle methods](https://facebook.github.io/react/docs/component-specs.html) pass in their own associated arguments \u0026mdash; for example the `render` method will take `props`, `context` and `dispatch`, whereas other functions such as `componentWillUpdate` would also take an additional `nextProps` argument.\n\n## Nonstandard Properties\n\nBelow are a handful of additional nonstandard properties which can be destructured in **all** lifecycle methods.\n\n* [`id`](#id) \u0026mdash; for managing local state in the Redux tree structure;\n* [`args`](#args) \u0026mdash; accessing **all** arguments for passing to other functions;\n\n### `id`\n\nFor managing [pseudo-local state](https://github.com/reactjs/redux/issues/159) in a single tree state you can use the `id` property \u0026mdash; which is a unique [`Symbol`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Symbol) representing the current component. When dispatching actions you should pass the `id` as the payload, and then pass the `id` back as part of the result \u0026mdash; with that information it's simple to determine when a component *should* be updated.\n\n```javascript\nconst render = ({ id }) =\u003e {\n    return \u003ca onClick={dispatch(setValueFor(id, 'United Kingdom'))}\u003e\u003c/a\u003e;\n};\n```\n\nYou may also prevent other components from updating by using the `shouldComponentUpdate` function to determine when the action applies to the current component. It's worth noting that a custom `shouldComponentUpdate` will simply be composed with the Keo default `shouldComponentUpdate` which inspects the `propTypes` for a significant performance enhancement.\n\n```javascript\nconst shouldComponentUpdate = ({ id, props }) =\u003e {\n    return props.select.id === id;\n};\n```\n\n**Note:** Will also check `propTypes` if they have been defined on the component.\n\n### `args`\n\nIn [Haskell](https://www.haskell.org/) you have `all@` for accessing **all** of the arguments in a function, even after listing the arguments individually \u0026mdash; with JavaScript you have the nonstandard `arguments` however with Keo `args` can be destructured to provide access to **all** of the arguments passed in, allowing you to forward these arguments to other functions.\n\n```javascript\nconst greetingIn = (language, { props }) =\u003e {\n    switch (language) {\n        case 'en': return `Hello ${props.name}`;\n        case 'de': return `Guten Tag ${props.name}`;\n    }\n};\n\nconst render = ({ props, context, args }) =\u003e {\n    const greeting = greetingIn('en', args);\n    // ...\n    return \u003ch1\u003e${greeting}!\u003c/h1\u003e\n};\n```\n\nWhich then allows you to destructure the arguments in the `greetingIn` function as though it's a typical lifecycle React method.\n\n## Testing Smart Components\n\nWhenever you pass the `mapStateToProps` argument to Keo's `stitch` function you create a [smart component](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) \u0026mdash; due to the wrapping that `react-redux` applies to these components they can be troublesome to test. As such they should ideally be exported as both a smart component for your application **and** as a dumb component for unit testing.\n\nHowever Keo provides a convenient `unwrap` function to resolve smart components to dumb components for testing purposes \u0026mdash; leaving your application to handle the smart components.\n\n**Component:**\n\n```javascript\nimport { stitch } from 'keo';\n\nconst render = ({ props }) =\u003e {\n    return \u003ch1\u003eHi {props.name}\u003c/h1\u003e;\n};\n\nexport default stitch({ render }, state =\u003e state);\n```\n\n**Unit Test:**\n\n```javascript\nimport test from 'ava';\nimport { unwrap } from 'keo';\nimport Greet from './component';\n\ntest('We can unwrap the smart component for testing purposes', t =\u003e {\n\n    const UnwrappedGreet = unwrap(Greet);\n    const component = \u003cUnwrappedGreet name=\"Philomena\" /\u003e;\n    \n    // ...\n    \n    t.pass();\n    \n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWildhoney%2FKeo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FWildhoney%2FKeo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWildhoney%2FKeo/lists"}