やったこと
- redux-formを使ってReactで投稿画面を実装した
- axiosを使って、Railsで実装したAPIと連携させ、投稿できるようにした。
成果物
実装手順
モジュールのインストール
アプリ開発全体で使うモジュールはここでインストールしています。
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)