상세 컨텐츠

본문 제목

Blog App 4 StreamCreate

React

by nata_developer 2020. 8. 20. 14:48

본문

0.앱 구조

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

 

1.api/streams.js

npm i axios
import axios from "axios"

export default axios.create({
    baseURL: "http://localhost:3001"
})

axios의 baseURL을 설정하여 axios가 필요한 곳에 가져다 쓴다.

 

2.actions/index.js

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이 호출되면 "/"로 이동한다.

 

2.src/App.js

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;

 

3.components/streams/streamForm.js

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>
    );
  }

 

4.src/components/streams/streamCreate.js

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);

'React' 카테고리의 다른 글

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

관련글 더보기