読者です 読者をやめる 読者になる 読者になる

あいつの日誌β

あいつの日誌です。

React tutorial (8)

React.js Redux Tutorial

react-select

前回は redux-form について触れました。 今回は react-select について触れます。

目次

  • 開発環境を準備
  • React の基本的な Life Cycle に触れる
  • redux に触れる
  • redux-saga に触れる
  • react router に触れる
  • npm で公開されている components を導入して echo system を体感する
  • redux-form に触れる
  • react-select に触れる <= 今日やること

今日やること

f:id:okamuuu:20170125231453g:plain

準備

npm install --save react-select

各種ファイル作成

touch src/components/Form.js

create src/components/Form.js

import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form'
import Select from 'react-select'
import 'react-select/dist/react-select.css'

export const renderField = ({ input, label, type, meta: { touched, error } }) => (
  <div className="form-group">
    <label htmlFor={label}>{label}</label>
    <input className="form-control" {...input} placeholder={label} type={type}/>
    <p className="text-danger">{touched && (error && <span>{error}</span>)}</p>
  </div>
)

export const renderTextAreaField = ({ input, label, type, meta: { touched, error } }) => (
  <div className="form-group">
    <label htmlFor={label}>{label}</label>
    <textarea className="form-control" {...input} placeholder={label} type={type} rows="10"/>
    <p className="text-danger">{touched && (error && <span>{error}</span>)}</p>
  </div>
)

export const renderSelectField = ({ input, label, options,  meta: { touched, error } }) => {
  return (
    <div className="form-group">
      <label htmlFor={label}>{label}</label>
      <Select
        name={input.name}
        value={input.value}
        onChange={input.onChange}
        onBlur={() => input.onBlur(input.value)}
        options={options}
        placeholder="Select"
        simpleValue
        clearable={false}
      />
      <p className="text-danger">{touched && (error && <span>{error}</span>)}</p>
    </div>
  )
}

export const renderSelectMultiField = ({ input, label, options, meta: { touched, error } }) => {
  return (
    <div className="form-group">
      <label htmlFor={label}>{label}</label>
      <Select
        {...input}
        onBlur={() => input.onBlur([...input.value].map(x => (x.value)))}
        options={options}
        multi
      />
      <p className="text-danger">{touched && (error && <span>{error}</span>)}</p>
    </div>
  )
}

edit src/containers/CreatePost.js

import React, {Component} from 'react'
import { connect } from 'react-redux'
import { Field, reduxForm } from 'redux-form'
import { createPost } from '../actions'
import { renderField, renderTextAreaField, renderSelectField, renderSelectMultiField } from '../components/Form'

const userOptions = [
  {value: 1, label: "userOne"},
  {value: 2, label: "userTwo"},
  {value: 3, label: "userThuree"},
]

const tagsOptions = [
  {value: "foo", label: "foo"},
  {value: "bar", label: "bar"},
  {value: "hoge", label: "hoge"},
  {value: "fuga", label: "fuga"},
]

let PostForm = (props) => {
  const { handleSubmit, pristine, submitting } = props
  return (
    <form onSubmit={handleSubmit}>
      <Field name="userId" label="User" component={renderSelectField} options={userOptions} />
      <Field name="title" type="text" label="Title" component={renderField} />
      <Field name="tags" label="Tags" component={renderSelectMultiField} options={tagsOptions} />
      <Field name="body" type="text" label="Body" component={renderTextAreaField} />
      <div style={{marginTop: "30px"}}>
        <button className="btn btn-primary" type="submit" disabled={pristine || submitting}>Submit</button>
      </div>
    </form>
  )
}

const validate = values => {
  const errors = {}

  if (!values.title) {
    errors.title = 'Required'
  } else if (values.title.length > 15) {
    errors.title = 'Must be 15 characters or less'
  }

  if (!values.body) {
    errors.body = 'Required'
  }

  return errors
}

PostForm = reduxForm({
    form: "post",
    validate,
    enableReinitialize: true,
})(PostForm)

class CreatePost extends Component {

  handleSubmit() {
    const params = this.props.form.post.values
    // Note: the resource will not be really created on the server but it will be faked as if.
    this.props.dispatch(createPost({params}))
  }

  render() {
    return (
      <PostForm onSubmit={this.handleSubmit.bind(this)} />
    )
  }
}

const select = state => (state)

export default connect(select)(CreatePost)

まとめ

以上全8回に分けて React.js で SPA の作り方を紹介しました。将来的に自分が React.js の事を忘れた時に備えた記事ですが、どこかで誰かの役に立てばうれしいです。

なのですがそういえば DatePicker の事を書くのを忘れていました。 ということであとちょっとだけ続きます。