1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Example: Form handler with Redux and React-bootstrap (#2949)

* Example: Form handler with Redux and React-bootstrap

* inputChange refactoring

* Destructuring inputChange
This commit is contained in:
estrada9166 2017-09-19 14:24:28 -05:00 committed by Tim Neutkens
parent d03ce5386d
commit 4bd30c8713
16 changed files with 300 additions and 0 deletions

View file

@ -0,0 +1,30 @@
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/form-handler)
# Form Handler
## How to use
Download the example [or clone the repo](https://github.com/zeit/next.js):
```bash
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/form-handler
cd form-handler
```
Install it and run:
```bash
npm install
npm run dev
```
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
```bash
now
```
## The idea behind the example
Sometimes handle multiple forms can be tricky, the idea is to have a global reducer
with the name of each form and the inputs of it; making accessible everywhere.

View file

@ -0,0 +1,5 @@
import { INPUT_VALUE } from '../constants'
export const inputChange = (title, name, val) => dispatch => {
return dispatch({type: INPUT_VALUE, title, name, val})
}

View file

@ -0,0 +1 @@
export * from './formActionsCreators'

View file

@ -0,0 +1,26 @@
import React, {Component} from 'react'
import { Col, Row } from 'react-bootstrap'
import { connect } from 'react-redux'
class DisplayForm extends Component {
render () {
const { state } = this.props
return (
<div>
<Row>
<Col lg={8} lgOffset={2}>
<pre>{JSON.stringify(state, null, 2) }</pre>
</Col>
</Row>
</div>
)
}
}
const mapStateToProps = state => {
return {
state
}
}
export default connect(mapStateToProps)(DisplayForm)

View file

@ -0,0 +1,17 @@
import { Col, Row, Jumbotron } from 'react-bootstrap'
const Header = () => {
return (
<div>
<Row style={{ marginTop: '10px' }}>
<Col lg={8} lgOffset={2}>
<Jumbotron style={{ borderRadius: '15px' }}>
<h1 style={{textAlign: 'center'}}>Form Handler</h1>
</Jumbotron>
</Col>
</Row>
</div>
)
}
export default Header

View file

@ -0,0 +1,26 @@
import { Col, Row } from 'react-bootstrap'
import Input from '../handlers/Input'
const Social = () => {
return (
<div>
<Row>
<Col lg={8}>
<Input controlLabel='Facebook' title='social' name='facebook' />
</Col>
<Col lg={8}>
<Input controlLabel='Instagram' title='social' name='instagram' />
</Col>
<Col lg={8}>
<Input controlLabel='Twitter' title='social' name='twitter' />
</Col>
<Col lg={8}>
<Input controlLabel='Github' title='social' name='github' />
</Col>
</Row>
</div>
)
}
export default Social

View file

@ -0,0 +1,26 @@
import { Col, Row } from 'react-bootstrap'
import Input from '../handlers/Input'
const UserForm = () => {
return (
<div>
<Row>
<Col lg={8} lgOffset={4}>
<Input controlLabel='Name' title='user' name='name' />
</Col>
<Col lg={8} lgOffset={4}>
<Input controlLabel='Last name' title='user' name='lastName' />
</Col>
<Col lg={8} lgOffset={4}>
<Input controlLabel='Email' type='email' title='user' name='email' />
</Col>
<Col lg={8} lgOffset={4}>
<Input controlLabel='Password' type='password' title='user' name='password' />
</Col>
</Row>
</div>
)
}
export default UserForm

View file

@ -0,0 +1,34 @@
import React, {Component} from 'react'
import Head from 'next/head'
import { Col, Row } from 'react-bootstrap'
import Header from './Header'
import DisplayForm from './DisplayForm'
import UserForm from './UserForm'
import Social from './Social'
class Main extends Component {
render () {
return (
<div>
<Head>
<title>Form Handler</title>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css' />
</Head>
<Header />
<DisplayForm />
<Row>
<Col lg={6}>
<UserForm />
</Col>
<Col lg={6}>
<Social />
</Col>
</Row>
</div>
)
}
}
export default Main

View file

@ -0,0 +1 @@
export const INPUT_VALUE = 'INPUT_VALUE'

View file

@ -0,0 +1,38 @@
import React, {Component} from 'react'
import { FormGroup, ControlLabel, FormControl } from 'react-bootstrap'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { inputChange } from '../actions'
class Input extends Component {
inputChange = (e) => {
const { inputChange, title, name } = this.props
inputChange(title, name, e.target.value)
}
render () {
return (
<div>
<FormGroup controlId='formBasicText'>
<ControlLabel>{this.props.controlLabel}</ControlLabel>
<FormControl
disabled={this.props.disabled}
type={this.props.type || 'Text'}
placeholder={this.props.controlLabel}
onChange={this.inputChange}
value={this.props.val}
/>
</FormGroup>
</div>
)
}
}
const mapDispatchToProps = dispatch => {
return {
inputChange: bindActionCreators(inputChange, dispatch)
}
}
export default connect(null, mapDispatchToProps)(Input)

View file

@ -0,0 +1,26 @@
{
"name": "redux-form",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "next start -p 8000",
"dev": "node server.js",
"build": "next build"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.15.4",
"next": "^3.2.2",
"next-redux-wrapper": "^1.3.2",
"react": "^15.6.1",
"react-bootstrap": "^0.31.3",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0"
}
}

View file

@ -0,0 +1,14 @@
import React, { Component } from 'react'
import withRedux from 'next-redux-wrapper'
import Main from '../components'
import { initStore } from '../store'
class Index extends Component {
render () {
return <Main />
}
}
export default withRedux(initStore, null)(Index)

View file

@ -0,0 +1,15 @@
import { INPUT_VALUE } from '../constants'
export default (state = {}, action) => {
switch (action.type) {
case INPUT_VALUE:
return { ...state,
[action.title]:
{ ...state[action.title],
[action.name]: action.val
}
}
default:
return state
}
}

View file

@ -0,0 +1,6 @@
import { combineReducers } from 'redux'
import formReducer from './formReducer'
export default combineReducers({
formReducer
})

View file

@ -0,0 +1,28 @@
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
server.get('/', (req, res) => {
return handle(req, res)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})

View file

@ -0,0 +1,7 @@
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import reducer from './reducers'
export const initStore = (initialState = {}) => {
return createStore(reducer, initialState, applyMiddleware(thunkMiddleware))
}