LoginSignup
0
1

More than 3 years have passed since last update.

redux-formを使って投稿画面を実装する【初学者のReact×Railsアプリ開発 第7回】

Last updated at Posted at 2020-01-13

やったこと

  • redux-formを使ってReactで投稿画面を実装した
  • axiosを使って、Railsで実装したAPIと連携させ、投稿できるようにした。

成果物

ohy01-019mn.gif

実装手順

モジュールのインストール

アプリ開発全体で使うモジュールはここでインストールしています。

App.js

App.js
import Login from './containers/Create';

            <Auth>
              <Switch>
                <Route exact path="/" component={Home} />
                <Route path='/create' component={Create} />
              </Switch>
            </Auth>

reducers/rootReducer.js

  • redux-formからformReducerを読み込んでいる。
rootReducer.js
import { combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'
import { routerReducer } from 'react-router-redux'
import CurrentUserReducer from './CurrentUserReducer'

const rootReducer = combineReducers({
  CurrentUserReducer,
  form: formReducer,
  router: routerReducer,
})

export default rootReducer

containers/Create.js

  • これが投稿画面。
  • フォームCreateForm.jsをインポートしている
  • submitPostで送信の処理を書いている。
  • フォーム内の改行などはreplaceなどを使って消去している
  • axiosの使い方はここで書いている通りで、localStorageからauth_tokenなどを呼び出して、headerにつけて送っていることで認証できる。
  • 送信後のフォームの処理は、本当はactionを経由しなければいけないのかな〜...(この実装方法だと、タイミングは微妙に変)
Create.js
import React from 'react'
import CreateForm from '../components/CreateForm'
import axios from 'axios'

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import * as actions from '../actions';

class Create extends React.Component {
  constructor(props) {
    super()
    this.state = {
      postSuccess: false,
    }
  }
  submit = values => {
    const data = {
      content: values.notes,
      user_id: 1
    }
    axios.post(process.env.REACT_APP_API_URL + '/api/v1/posts', data)
  }

  submitPost = values => {
    const { CurrentUserReducer } = this.props;
    var value_content = values.notes
    var send_content = value_content.replace(/\r?\n/g, "");

    const data = {
      content: send_content,
      user_id: CurrentUserReducer.items.id
    }
    const auth_token = localStorage.auth_token
    const client_id = localStorage.client_id
    const uid = localStorage.uid

    axios.post(process.env.REACT_APP_API_URL + '/api/v1/posts', data, {
      headers: {
        'access-token': auth_token,
        'client': client_id,
        'uid': uid
      }
    })
      .then(() => {
      })
      .catch(() => {
        values.notes = value_content
      })
    values.notes = ""

  }

  render() {
    const { actions } = this.props;
    const { CurrentUserReducer } = this.props;

    const { classes } = this.props;
    return (
      <div>
        <h3>テーマを投稿する</h3>
        <CreateForm onSubmit={this.submitPost} />
      </div>
    )
  }
}

const mapState = (state, ownProps) => ({
  CurrentUserReducer: state.CurrentUserReducer
});

function mapDispatch(dispatch) {
  return {
    actions: bindActionCreators(actions, dispatch),
  };
}

export default connect(mapState, mapDispatch)(Create);

components/CreateForm.js

  • validateで必須項目や50字以内にするように指定している。
  • const CreateForm内のFieldタグで色々オプションを付けている。multilineは複数行のフォームにするかどうか?で、rowsMaxで最大の行数を指定できる。Enter押すと自動で行数が増えていく。
CreateForm.js
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import TextField from '@material-ui/core/TextField'
import Button from '@material-ui/core/Button';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  button: {
    margin: theme.spacing(1),
  },
  field: {
    width: '80%',
    height: '200px',
  }
}));

const validate = values => {
  const errors = {}
  const requiredFields = [
    'notes'
  ]
  requiredFields.forEach(field => {
    if (!values[field]) {
      errors[field] = 'Required'
    }
  })
  if (
    values.notes &&
    values.notes.length > 51
  ) {
    errors.notes = '50字以内にしてください'
  }
  return errors
}

const renderTextField = ({
  label,
  input,
  meta: { touched, invalid, error },
  rows = 3,
  ...custom
}) => (
    <TextField
      label={label}
      placeholder={label}
      error={touched && invalid}
      helperText={touched && error}
      {...input}
      rows={rows}
      {...custom}
      variant="outlined"
    />
  )

const CreateForm = props => {
  const { handleSubmit, pristine, reset, submitting } = props
  const classes = useStyles();
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <Field
          name="notes"
          component={renderTextField}
          className={classes.field}
          label=""
          multiline
          rowsMax="7"
          margin="normal"
        />
      </div>
      <div>
        <Button
          variant="contained"
          color="primary"
          type="submit"
          className={classes.button}
        //endIcon={<Icon>send</Icon>}
        >
          Send
      </Button>
      </div>
    </form>
  )
}

export default reduxForm({
  form: 'CreateForm', // a unique identifier for this form
  validate,
})(CreateForm)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1