UNPKG

@mjackson/my-react

Version:

A lightweight, drop-in replacement for React that avoids using ES6 classes and "this"

160 lines (117 loc) 3.92 kB
# myReact myReact is a lightweight, drop-in replacement for React that avoids using ES6 classes and `this`. In myReact, you don't create classes or extend `React.Component`. Instead, you just export a bunch of functions from a JavaScript module. Instead of using `this` to access the component instance in methods, _every method_ receives the instance as the first argument, usually called `my` (similar to how instance methods in Python always receive `self` as the initial argument). This helps developers avoid many common mistakes including: * forgetting to bind the appropriate `this` in event handler methods * getting the correct `this` inside inline event handlers in the `render` method * getting the correct `this` inside `forEach`/`map` in the `render` method Other minor improvements to the ES6 class-based React component API include: * `setupComponent` instead of `constructor`; avoids the `super` boilerplate * `getNextState` instead of `componentWillReceiveProps`; automatically applies the return value to `my.state` * `getElement` instead of `render`; it's more descriptive Now, I know, that sounds like a lot. Let's see what it looks like! Here's how you might create a simple `<TodoList>` component: ```js import MyReact from "@mjackson/my-react" const displayName = "TodoList" const defaultProps = { title: "Todo List", initialItems: [] } function setupComponent(my) { my.state = { items: my.props.initialItems } } function handleSubmit(my, event) { event.preventDefault() const todo = my.refs.todo my.setState({ items: my.state.items.concat([todo.value]) }) todo.form.reset() } function getElement(my) { return ( <div> <h1>{my.props.title}</h1> <ol>{my.state.items.map(item => <li>{item}</li>)}</ol> <form onSubmit={my.handleSubmit}> <input ref="todo" type="text" /> </form> </div> ) } export default { displayName, defaultProps, setupComponent, handleSubmit, getElement } ``` Assuming the above code was saved in `TodoList.js`, you could use it just like any other React component (see [Usage](#usage) below): ```js import MyReact from "@mjackson/my-react" import ReactDOM from "react-dom" import TodoList from "./TodoList" const node = document.getElementById("app") ReactDOM.render(<TodoList />, node) ``` You can also put your own properties on the `my` object that aren't needed for rendering, like timers and references to in-flight XHR objects. Each time a lifecycle method is invoked for a given component, it receives the _same instance_. Note in the following example how `my.timer` is set in `componentDidMount` and then cleaned up in `componentWillUnmount`. ```js import MyReact from "@mjackson/my-react" const displayName = "Counter" function setupComponent(my) { my.state = { count: 0 } } function componentDidMount(my) { my.timer = setInterval(() => { my.setState({ count: my.state.count + 1 }) }, 1000) } function componentWillUnmount(my) { clearInterval(my.timer) } function getElement(my) { return <p>The current count is {my.state.count}</p> } export default { displayName, setupComponent, componentDidMount, componentWillUnmount, getElement } ``` ## Installation yarn add @mjackson/my-react ## Usage Assuming you're already using Babel for compiling JSX, you can just do: ```js import MyReact from "@mjackson/my-react" // Tell Babel to transform JSX into MyReact.createElement calls /** @jsx MyReact.createElement */ ``` If you'd rather not put that comment in every file where you're using JSX, you can just put the following in your `.babelrc`: ```json { "plugins": ["transform-react-jsx", { "pragma": "MyReact.createElement" }] } ``` ## Feedback I'd love to get some feedback on this approach. Please feel free to reach out [on Twitter](https://twitter.com/mjackson) or [GitHub](https://github.com/mjackson/my-react'). Thanks!