├── .babelrc
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── __snapshots__
└── test.js.snap
├── examples
├── App.js
├── Counter.js
├── Demo.js
├── List.js
├── README.md
├── package.json
└── updaters.js
├── package.json
├── src
└── index.js
└── test.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env",
4 | "stage-0",
5 | "react"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | package-lock.json
4 | dist
5 | .nyc_output
6 | coverage
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | docs
3 | examples
4 | .nyc_output
5 | coverage
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 8
4 | after_success:
5 | - npm run cover
6 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | # The MIT License (MIT)
3 | Copyright (c) 2017 Brent Jackson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Refunk 🎧
3 |
4 | Simple React functional setState
5 | with the new [React context API][context] (requires React v16.3 or later)
6 |
7 |
8 | ```sh
9 | npm i refunk
10 | ```
11 |
12 | ## Getting Started
13 |
14 | ```jsx
15 | import React from 'react'
16 | import { connect } from 'refunk'
17 |
18 | // Create a state provider component
19 | const App = connect(props => (
20 |
21 |
count: {props.count}
22 |
23 |
24 | ))
25 |
26 | // Updaters are functions that return state
27 | const dec = state => ({ count: state.count - 1 })
28 | const inc = state => ({ count: state.count + 1 })
29 |
30 | // Connect the Controls component to the App state
31 | const Controls = connect(props => (
32 |
33 | {props.count}
34 |
37 |
40 |
41 | ))
42 |
43 | const initialState = {
44 | count: 0
45 | }
46 |
47 | // initialize state with props
48 | render()
49 | ```
50 |
51 | ## Usage
52 |
53 | Refunk components initialize state from props and provide an `update` function to their consumers.
54 | When nesting Refunk components, the top-most component will control state for any child Refunk components.
55 |
56 | The `update` function works the same as `setState`, but it's intended to be used with separate [updater functions](#using-updaters),
57 | that can be shared across many parts of an application.
58 |
59 | ### connect
60 |
61 | The `connect` higher-order component creates state based on props for top-level components or connects into a parent Refunk component's state when nested.
62 | This allows for the creation of stateful components that can work standalone or listen to a parent's state.
63 |
64 | ```jsx
65 | import React from 'react'
66 | import { connect } from 'refunk'
67 |
68 | const App = connect(props => (
69 |
70 | {props.count}
71 |
72 | ))
73 |
74 | App.defaultProps = {
75 | count: 0
76 | }
77 |
78 | export default App
79 | ```
80 |
81 | ### Provider
82 |
83 | For lower-level access to React's context API, the Provider component can be used to create a context.
84 | The Refunk Provider will convert props to initial state and provide the state and `update` function through context.
85 |
86 | ```jsx
87 | import React from 'react'
88 | import { Provider } from 'refunk'
89 |
90 | const App = props => (
91 |
92 |
93 |
94 | )
95 | ```
96 |
97 | ### Consumer
98 |
99 | The context Consumer is also exported for lower-level access to the context API.
100 |
101 | ```jsx
102 | import React from 'react'
103 | import { Provider, Consumer } from 'refunk'
104 |
105 | const inc = state => ({ count: state.count + 1 })
106 |
107 | const App = props => (
108 |
109 |
110 | {state => (
111 |
112 | {state.count}
113 |
114 |
115 | )}
116 |
117 |
118 | )
119 | ```
120 |
121 | ### Using Updaters
122 |
123 | Updaters are functions that are passed to the `props.update()` function.
124 | An updater function takes `state` as its only argument and returns a new state.
125 |
126 | ```jsx
127 | // updaters.js
128 | // Create an `updaters` module with functions to update the state of the app
129 | export const decrement = state => ({ count: state.count - 1 })
130 | export const increment = state => ({ count: state.count + 1 })
131 | ```
132 |
133 | ```jsx
134 | // Counter.js
135 | // Use the updater functions in the connected Counter component
136 | import React from 'react'
137 | import { connect } from 'refunk'
138 | import { decrement, increment } from './updaters'
139 |
140 | const Counter = props => (
141 |
167 | )
168 |
169 | export default connect(App)
170 | ```
171 |
172 | ## Build Your Own
173 |
174 | Refunk's [source](src) is only about 50 LOC and relies on built-in React functionality.
175 | This library is intended to be used directly as a package and also to serve as an example of some ways to handle state in a React application.
176 | Feel free to fork or steal ideas from this project, and build your own version.
177 |
178 |
179 | ## Concepts
180 |
181 | Refunk is meant as a simpler, smaller alternative to other state
182 | managment libraries that makes use of React's built-in component state.
183 | Refunk uses higher-order components, the new [context API][context], and React component state management along with
184 | [functional setState][setState]
185 | to help promote the separation of presentational and container components,
186 | and to keep state updating logic outside of the components themselves.
187 |
188 | This library also promotes keeping application state in a single location,
189 | similar to other [Flux][flux] libraries and [Redux][redux].
190 |
191 |
192 | ### Related
193 |
194 | - [microstate](https://github.com/estrattonbailey/microstate)
195 | - [statty](https://github.com/vesparny/statty)
196 | - [unistore](https://github.com/developit/unistore)
197 | - [redux][redux]
198 | - [unstated](https://github.com/jamiebuilds/unstated)
199 |
200 | [context]: https://reactjs.org/docs/context.html
201 | [setState]: https://facebook.github.io/react/docs/react-component.html#setstate
202 | [flux]: http://facebook.github.io/flux/
203 | [redux]: http://redux.js.org/
204 |
205 | ---
206 |
207 | [Made by Jxnblk](http://jxnblk.com) | [MIT License](LICENSE.md)
208 |
--------------------------------------------------------------------------------
/__snapshots__/test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Component renders 1`] = `
4 |
5 | Hello
6 |
7 | `;
8 |
--------------------------------------------------------------------------------
/examples/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from '..'
3 | import Counter from './Counter'
4 | import List from './List'
5 |
6 | const App = connect(props => (
7 |