blog-app
api
db.json
client
public
index.html
modal.html
src
actions
index.js
types.js
apis
streams.js
components
StreamCreate.js
StreamDelete.js
StreamEdit.js
StreamForm.js
StreamList.js
App.js
GoogleAuth.js
Header.js
Modal.js
reducers
authReducer.js
index.js
streamReducer.js
history.js
index.js
npm i axios
import axios from "axios"
export default axios.create({
baseURL: "http://localhost:3001"
})
axios의 baseURL을 설정하여 axios가 필요한 곳에 가져다 쓴다.
import {
SIGN_IN,
SIGN_OUT,
CREATE_STREAM,
FETCH_STREAMS,
FETCH_STREAM,
DELETE_STREAM,
EDIT_STREAM,
} from "./types";
import history from "../history";
import streams from "../apis/streams";
export const signIn = (userId) => {
return {
type: SIGN_IN,
payload: userId,
};
};
export const signOut = () => {
return {
type: SIGN_OUT,
};
};
export const createStream = formValues => async (dispatch, getState) => {
const { userId } = getState().auth;
const response = await streams.post('/streams', { ...formValues, userId });
dispatch({ type: CREATE_STREAM, payload: response.data });
history.push('/');
};
export const fetchStreams = () => async dispatch => {
const response = await streams.get('/streams');
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
export const fetchStream = id => async dispatch => {
const response = await streams.get(`/streams/${id}`);
dispatch({ type: FETCH_STREAM, payload: response.data });
};
export const editStream = (id, formValues) => async (dispatch) => {
const response = await streams.patch(`streams/${id}`, formValues);
dispatch({ type: EDIT_STREAM, payload: response.data });
history.push("/")
};
export const deleteStream = (id) => async (dispatch) => {
await streams.delete(`/streams/${id}`);
dispatch({ type: DELETE_STREAM, payload: id });
history.push('/');
};
CreateStream
export const createStream = (formValues) => async (dispatch, getState) => {
const { userId } = getState().auth;
const response = await streams.post("/streams", { ...formValues, userId });
dispatch({ type: CREATE_STREAM, payload: response.data });
history.push("/");
};
getState를 통해 현재 Store에 저장되어 있는 데이터를 가져온다.
const { userId } = getState().auth는 Store의 authReducer에 있는 userId를 가져오는 것이다.
dispatch를 통해 streamsReducer에 보내고, 처리된 상태를 Store에 저장한다.
또한 createStream이 호출되면 "/"로 이동한다.
import React from "react";
import { Router, Route } from "react-router-dom";
import Header from "./Header";
import StreamList from "./streams/StreamList";
import StreamShow from "./streams/StreamShow";
import StreamDelete from "./streams/StreamDelete";
import StreamEdit from "./streams/StreamEdit";
import StreamCreate from "./streams/StreamCreate";
import history from "../history"
class App extends React.Component {
render() {
return (
<div className="ui container">
<Router history={history}>
<div>
<Header />
<Route path="/" exact component={StreamList} />
<Route path="/streams/new" exact component={StreamCreate} />
<Route path="/streams/edit/:id" exact component={StreamEdit} />
<Route path="/streams/delete/:id" exact component={StreamDelete} />
<Route path="/streams/show" exact component={StreamShow} />
</div>
</Router>
</div>
);
}
}
export default App;
import React from 'react';
import { Field, reduxForm } from 'redux-form';
class StreamForm extends React.Component {
renderError({ error, touched }) {
if (touched && error) {
return (
<div className="ui error message">
<div className="header">{error}</div>
</div>
);
}
}
renderInput = ({ input, label, meta }) => {
const className = `field ${meta.error && meta.touched ? 'error' : ''}`;
return (
<div className={className}>
<label>{label}</label>
<input {...input} autoComplete="off" />
{this.renderError(meta)}
</div>
);
};
onSubmit = formValues => {
this.props.onSubmit(formValues);
};
render() {
return (
<form
onSubmit={this.props.handleSubmit(this.onSubmit)}
className="ui form error"
>
<Field name="title" component={this.renderInput} label="Enter Title" />
<Field
name="description"
component={this.renderInput}
label="Enter Description"
/>
<button className="ui button primary">Submit</button>
</form>
);
}
}
const validate = formValues => {
const errors = {};
if (!formValues.title) {
errors.title = 'You must enter a title';
}
if (!formValues.description) {
errors.description = 'You must enter a description';
}
return errors;
};
export default reduxForm({
form: 'streamForm',
validate
})(StreamForm);
에러처리
renderError({ error, touched }) {
if (touched && error) {
return (
<div className="ui error message">
<div className="header">{error}</div>
</div>
);
}
}
reduxForm을 props로 받는다.
this.props.error, this.props.touched가 있을 경우 에러 메세지를 보낸다.
Input
renderInput = ({ input, label, meta }) => {
const className = `field ${meta.error && meta.touched ? 'error' : ''}`;
return (
<div className={className}>
<label>{label}</label>
<input {...input} autoComplete="off" />
{this.renderError(meta)}
</div>
);
};
Validation
const validate = formValues => {
const errors = {};
if (!formValues.title) {
errors.title = 'You must enter a title';
}
if (!formValues.description) {
errors.description = 'You must enter a description';
}
return errors;
};
onSubmit
props를 통해각 컴포넌트와 연결된다.
src/components/streams/streamCreate.js
onSubmit = formValues => {
this.props.createStream(formValues);
};
render() {
return (
<div>
<h3>Create a Stream</h3>
<StreamForm onSubmit={this.onSubmit} />
</div>
);
}
}
src/components/streams/streamEdit.js
onSubmit = formValues => {
this.props.editStream(this.props.match.params.id, formValues);
};
render() {
if (!this.props.stream) {
return <div>Loading</div>;
}
return (
<div>
<h3>Edit a Stream</h3>
<StreamForm
initialValues={_.pick(this.props.stream, 'title', 'description')}
onSubmit={this.onSubmit}
/>
</div>
);
}
import React from 'react';
import { connect } from 'react-redux';
import { createStream } from '../../actions';
import StreamForm from './StreamForm';
class StreamCreate extends React.Component {
onSubmit = formValues => {
this.props.createStream(formValues);
};
render() {
return (
<div>
<h3>Create a Stream</h3>
<StreamForm onSubmit={this.onSubmit} />
</div>
);
}
}
export default connect(
null,
{ createStream }
)(StreamCreate);
Blog App5 StreamEdit (0) | 2020.08.20 |
---|---|
redux-form (0) | 2020.08.20 |
Blog App 2 GoogleAuth (0) | 2020.08.20 |
react-router-dom (0) | 2020.08.20 |
Blog App 1 Scaffold (0) | 2020.08.20 |