react-redux-local-form
Advanced tools
@@ -8,3 +8,5 @@ # Basic example | ||
npm install | ||
npm start | ||
localhost:3000 | ||
``` |
import * as loginConstants from '../constants/login' | ||
export function login(username, password) { | ||
export function attemptLogin(username, password) { | ||
return (dispatch) => { | ||
@@ -5,0 +5,0 @@ dispatch({ type: loginConstants.PENDING }) |
@@ -18,38 +18,7 @@ import React, { PureComponent } from 'react' | ||
const initialFormState = { | ||
form: {}, | ||
login: { | ||
error: null, | ||
pending: false | ||
} | ||
} | ||
const reducer = combineReducers({ | ||
form: formReducer, | ||
login: loginReducer | ||
}) | ||
const enhancer = compose( | ||
applyMiddleware(thunk), | ||
formEnhancer('form') | ||
) | ||
function mapFormStateToProps(state) { | ||
return { | ||
loginPending: state.login.pending, | ||
loginError: state.login.error | ||
} | ||
} | ||
function mapFormDispatchToProps(dispatch) { | ||
return { | ||
...bindActionCreators(loginActions, dispatch) | ||
} | ||
} | ||
class LoginForm extends PureComponent { | ||
handleSubmit = (form) => { | ||
const { login, onAuthToken, onUser } = this.props | ||
const { attemptLogin, onAuthToken, onUser } = this.props | ||
login(form.email, form.password) | ||
attemptLogin(form.email, form.password) | ||
.then(({ token, profile }) => { | ||
@@ -60,2 +29,3 @@ onAuthToken(token) | ||
} | ||
render() { | ||
@@ -96,4 +66,35 @@ const { form, loginPending, loginError } = this.props | ||
const initialFormState = { | ||
form: {}, | ||
login: { | ||
error: null, | ||
pending: false | ||
} | ||
} | ||
const reducer = combineReducers({ | ||
form: formReducer, | ||
login: loginReducer | ||
}) | ||
const enhancer = compose( | ||
applyMiddleware(thunk), | ||
formEnhancer('form') | ||
) | ||
function mapFormStateToProps(state) { | ||
return { | ||
loginPending: state.login.pending, | ||
loginError: state.login.error | ||
} | ||
} | ||
function mapFormDispatchToProps(dispatch) { | ||
return { | ||
...bindActionCreators(loginActions, dispatch) | ||
} | ||
} | ||
export default withForm(initialFormState, reducer, enhancer)( | ||
connectForm(mapFormStateToProps, mapFormDispatchToProps)(LoginForm) | ||
) |
@@ -8,3 +8,5 @@ # Login example | ||
npm install | ||
npm start | ||
localhost:3000 | ||
``` |
@@ -6,3 +6,3 @@ import * as loginConstants from '../constants/login' | ||
case loginConstants.PENDING: | ||
return { ...state, pending: true } | ||
return { ...state, pending: true, error: null } | ||
@@ -9,0 +9,0 @@ case loginConstants.COMPLETE: |
@@ -15,2 +15,6 @@ 'use strict'; | ||
var _formStoreShape = require('./formStoreShape'); | ||
var _formStoreShape2 = _interopRequireDefault(_formStoreShape); | ||
var _actions = require('./actions'); | ||
@@ -142,9 +146,9 @@ | ||
Field.propTypes = { | ||
path: _react.PropTypes.string, | ||
validate: _react.PropTypes.any, | ||
children: _react.PropTypes.any | ||
path: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.array]).isRequired, | ||
validate: _react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.arrayOf(_react.PropTypes.func)]), | ||
children: _react.PropTypes.func.isRequired | ||
}; | ||
Field.contextTypes = { | ||
form: _react.PropTypes.object | ||
form: _formStoreShape2.default.isRequired | ||
}; | ||
exports.default = Field; |
@@ -7,2 +7,8 @@ 'use strict'; | ||
var _formStoreShape = require('./formStoreShape'); | ||
var _formStoreShape2 = _interopRequireDefault(_formStoreShape); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -57,3 +63,3 @@ | ||
FormProvider.propTypes = { | ||
store: _react.PropTypes.object, | ||
store: _react.PropTypes.object.isRequired, | ||
submitOnValue: _react.PropTypes.bool, | ||
@@ -64,4 +70,4 @@ onSubmit: _react.PropTypes.func, | ||
FormProvider.childContextTypes = { | ||
form: _react.PropTypes.object | ||
form: _formStoreShape2.default.isRequired | ||
}; | ||
exports.default = FormProvider; |
{ | ||
"name": "react-redux-local-form", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "React components for building forms with a local Redux store for managing state.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
React Redux Local Form | ||
========================= | ||
[](https://www.npmjs.com/package/react-redux-local-form) | ||
[](https://www.npmjs.com/package/react-redux-local-form) | ||
React Redux Local Form is a set of minimal React components to help with building forms. State is managed with a Redux store that is local to your component. This promotes keeping your [ui state separate from your global state](https://github.com/reactjs/redux/issues/1287#issuecomment-175351978) while still being able to leverage the redux ecosystem. You can also mix and match redux reducers/actions between local and global state. If these ideas appeal to you read on... if not, check out some of these great alternatives: | ||
React Redux Local Form is a set of minimal React components to help with building forms. State is managed with a Redux store that is local to your component. This promotes keeping your [ui state separate from your global state](https://github.com/reactjs/redux/issues/1287#issuecomment-175351978) while still being able to leverage the redux ecosystem. You can swap reducers/actions between local and global state as well apply different store enhancers to each level of state. If these ideas appeal to you read on... if not, check out some of these great alternatives: | ||
- [React Redux Form](https://github.com/davidkpiano/react-redux-form): Personal favourite, similar API. | ||
- [Redux Form](https://github.com/erikras/redux-form): More features out of the box, mature and most popular. | ||
- [React Forms](https://github.com/prometheusresearch/react-forms): No redux dependency | ||
- [Redux Form](https://github.com/erikras/redux-form): More features out of the box, mature and popular. | ||
- [React Forms](https://github.com/prometheusresearch/react-forms): Validate with JSONSchema, no redux dependency | ||
@@ -149,4 +149,6 @@ ## Installation | ||
## Advanced Usage | ||
`withForm` allows you to provide a custom reducer and enhancer that will be used to create the form store. This allows you to reuse reducers and bind actions to local component state. | ||
`withForm` also allows you to provide your own reducer and enhancer that will be used to create the form store. This allows you to reuse reducers and bind actions to local component state. You can also separate store enhancers depending on the level of state. A good use case for this is persisting and/or batching global state changes without affecting local state. | ||
You will need to manually apply the default reducer and enhancer. | ||
```js | ||
@@ -170,40 +172,7 @@ import React, { PureComponent } from 'react' | ||
const initialFormState = { | ||
// initial form state should reflect your combineReducers structure | ||
form: {}, | ||
login: { | ||
error: null, | ||
pending: false | ||
} | ||
} | ||
const reducer = combineReducers({ | ||
form: formReducer, | ||
login: loginReducer | ||
}) | ||
const enhancer = compose( | ||
applyMiddleware(thunk), | ||
// provide the key in state where form state exists (defined in combineReducers) | ||
formEnhancer('form') | ||
) | ||
function mapFormStateToProps(state) { | ||
return { | ||
loginPending: state.login.pending, | ||
loginError: state.login.error | ||
} | ||
} | ||
function mapFormDispatchToProps(dispatch) { | ||
return { | ||
...bindActionCreators(loginActions, dispatch) | ||
} | ||
} | ||
class LoginForm extends PureComponent { | ||
handleSubmit = (form) => { | ||
const { login, onAuthToken, onUser } = this.props | ||
const { attemptLogin, onAuthToken, onUser } = this.props | ||
login(form.email, form.password) | ||
attemptLogin(form.email, form.password) | ||
.then(({ token, profile }) => { | ||
@@ -214,2 +183,3 @@ onAuthToken(token) | ||
} | ||
render() { | ||
@@ -223,6 +193,6 @@ const { form, loginPending, loginError } = this.props | ||
{ ({ value = '', setValue, error }) => | ||
<section> | ||
<div> | ||
<label>Email { error && <div className="error">{ error.message }</div> }</label> | ||
<input type="text" value={value} onChange={targetValue(setValue)} /> | ||
</section> | ||
</div> | ||
} | ||
@@ -232,7 +202,6 @@ </Field> | ||
{ ({ value = '', setValue, error }) => | ||
<section> | ||
<div> | ||
<label>Password { error && <div className="error">{ error.message }</div> }</label> | ||
<input type="password" value={value} onChange={targetValue(setValue)} /> | ||
<small>Type 'error' to force a login error</small> | ||
</section> | ||
</div> | ||
} | ||
@@ -252,2 +221,35 @@ </Field> | ||
const initialFormState = { | ||
// initial form state should reflect your combineReducers structure | ||
form: {}, | ||
login: { | ||
error: null, | ||
pending: false | ||
} | ||
} | ||
const reducer = combineReducers({ | ||
form: formReducer, | ||
login: loginReducer | ||
}) | ||
const enhancer = compose( | ||
applyMiddleware(thunk), | ||
// provide the key in state where form state exists (defined in combineReducers) | ||
formEnhancer('form') | ||
) | ||
function mapFormStateToProps(state) { | ||
return { | ||
loginPending: state.login.pending, | ||
loginError: state.login.error | ||
} | ||
} | ||
function mapFormDispatchToProps(dispatch) { | ||
return { | ||
...bindActionCreators(loginActions, dispatch) | ||
} | ||
} | ||
export default withForm(initialFormState, reducer, enhancer)( | ||
@@ -254,0 +256,0 @@ connectForm(mapFormStateToProps, mapFormDispatchToProps)(LoginForm) |
@@ -5,2 +5,3 @@ import { PureComponent, PropTypes } from 'react' | ||
import formStoreShape from './formStoreShape' | ||
import * as actions from './actions' | ||
@@ -10,9 +11,15 @@ | ||
static propTypes = { | ||
path: PropTypes.string, | ||
validate: PropTypes.any, | ||
children: PropTypes.any | ||
path: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array | ||
]).isRequired, | ||
validate: PropTypes.oneOfType([ | ||
PropTypes.func, | ||
PropTypes.arrayOf(PropTypes.func) | ||
]), | ||
children: PropTypes.func.isRequired | ||
} | ||
static contextTypes = { | ||
form: PropTypes.object | ||
form: formStoreShape.isRequired | ||
} | ||
@@ -19,0 +26,0 @@ |
import { PureComponent, PropTypes, Children } from 'react' | ||
import formStoreShape from './formStoreShape' | ||
export default class FormProvider extends PureComponent { | ||
static propTypes = { | ||
store: PropTypes.object, | ||
store: PropTypes.object.isRequired, | ||
submitOnValue: PropTypes.bool, | ||
@@ -12,3 +14,3 @@ onSubmit: PropTypes.func, | ||
static childContextTypes = { | ||
form: PropTypes.object | ||
form: formStoreShape.isRequired | ||
} | ||
@@ -15,0 +17,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
62046
4.33%64
3.23%1250
3.82%257
0.78%