FrontEnd/React,Redux

PART6:Simply build App with Redux - Create / Redux Second Action

미스터황탄 2016. 9. 27. 18:40

Create Implementation

지난 포스팅에서 폼을 대상으로 smart / dumb 컴포넌트를 분리 했었다.

오늘은 게시글 추가(Create) 기능을 구현 할것인데 컴포넌트의 흐름과

게시글 리스트 호출외에 다른 action 에 따른 redux 의 흐름을 경험

해볼수 있을것 같다.

게시글을 새로 생성 하려면 먼저 무엇을 해야할까.?

우선 사용자가 입력한 폼에 있는 값을 가져와야 한다.

smart component 인 ManageBoard.js 파일 부터 수정하자.

계획은 이렇다.

intput[type="text"]onChange 될때 마다 새로운 state 값을 set 할것이다.

클래스 내부에서 호출할 props.contents 에 초기 객체를 설정해준다.

function mapStateToProps(state, ownProps) {
    let initContent = {
        id: '',
        title:'',
        content: '',
        author:'',
        date:''
    }

    return {
        contents : initContent
    }
}

생성자에 props.contents 를 호출해서 Object.assign 을 통해

immutable 한 객체를 state 초기값으로 설정해준다.

constructor(props, context) {
        super(props, context);

        this.state = {
            contents: Object.assign({}, props.contents)
        }
    }

onChange 에서 사용할 updateChangeState 함수를 구현 한다.

updateChangeState(event) {
        const field = event.target.name;
        let contents = this.state.contents;

        contents[field] = event.target.value;
        return this.setState({contents: contents});
    }

save 버튼이 눌렸을때 사용할 callWrite 함수를 구현 한다.

  callWrite(event) {
        event.preventDefault();
        console.log(this.state.contents);
    }

render() 에 있는 BoardForm 에 dumb Component 로 내려줄 props 를 정의 한다.

 render() {
        return (
            <BoardForm
                onChange={this.updateChangeState.bind(this)}
                onSave={this.callWrite.bind(this)} />
            );
    }

smart component 에서 props 를 내려줬으니 이제 dumb component 를 수정 해야 한다.

BoardForm.js 파일을 열자.

onChange 와 onSave 를 파라미터로 추가해서 FormInput 태그와 textarea 그리고 submit에

추가하고 propTypes 를 함수로 정의해준다.

const BoardForm = ({onChange, onSave}) => {
    return (
        <form>
        <h1>Write</h1>
            <FormInput name="author" label="Author" onChange={onChange} />
            <FormInput name="title" label="Title" onChange={onChange} />
            <div className="form-group">
             <label htmlFor="content">Content</label>
             <textarea name="content" id="content" className="form-control"
             onChange={onChange} ></textarea>
            </div>
             <input
                type="submit"
                value="Save"
                className="btn btn-primary"
                onClick={onSave}
                 />
        </form>
        );
}

BoardForm.propTypes = {
    onChange: PropTypes.func.isRequired,
    onSave : PropTypes.func.isRequired
}

BoardForm 에 하위로 FormInput 이 있으니 해당 컴포넌트도 수정해준다.

FormInput.js 파일을 열자

const FormInput = ({name, label, onChange}) => {
    return (
        <div className="form-group">
            <label htmlFor={name}>{label}</label>
            <input type="text"
                   name={name}
                   className="form-control" onChange={onChange} />
        </div>
        );
}

FormInput.propTypes = {
 name : PropTypes.string,
 label: PropTypes.string,
 onChange: PropTypes.func.isRequired
};

여기 까지 구현 했다면 다음과 같이 입력후 Save 를 클릭했을때

콘솔에서 폼값을 호출 하고 있는것을 확인 해볼수 있다.

 

이제 폼값을 가져 왔으니 폼값을 저장하는 일만 남았다.

액션 부터 생성하자.

actions 폴더에 actionTypes.js 에 상수를 추가 한다.

export const CALL_WRITE = 'CALL_WRITE';

api 폴더에 boardApi.jssaveContent 함수를 추가 한다.

      static saveContent(content) {
        content = Object.assign({}, content);
        return new Promise((resolve, reject) => {
                const minLength = 1;
                content.id = parseInt(contents[contents.length - 1].id) + 1
                content.date = new Date().toLocaleDateString().replace(/(\s*)/g,"").split('.').slice(0,3).join('/');
                contents.push(content);

                resolve(content);
        });
    }

id 와 date 를 생성해서 contents 배열에 push 했다.

이제 boardActions.js 파일로 이동 하자.

상단부에 actionTypes.js 에서 선언했던 CALL_WRITE 를 추가 하고

writeBoard 함수를 추가 한다.

export function writeBoard(content) {
    return (dispatch) => {
        return boardApi.saveContent(content)
        .then(content => dispatch({type : CALL_WRITE, content }))
        .catch(error => {
            throw(error);
        });
    }
}

다음은 흐름에 따라 reducers 폴더에 있는 boardReducer.js 로 이동 한다.

상단에 CALL_WRITE 를 추가하고 switch 문에 Action 을 추가 한다.

  case CALL_WRITE :
            return [
             ...state,
             Object.assign({}, action.content)
            ];

여기 까지 왔다면 redux 의 두번째 흐름이 거의 완성 단계에 왔다.

이제 smart componentManageBoard.js 로 가서 mapDispatchToProps

수정해줘야 한다.

상단부에 action 을 호출할것이고. bindActionCreators 를 사용할것 이다.

import * as boardActions from '../../actions/boardActions'; // 선언

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators(boardActions, dispatch)
    }
}

그리고 콘솔만 출력하던 callWrite 함수에서 boardActions 에 있는 writeBoard

Action 을 호출 하고 호출이 성공해서 게시글 작성이 완료되면 about 으로 이동할것 이다.

this.context.router 를 호출해주기 위해서 contextTypes 정의가 필요하다.

클래스 외부에 다음과 같이 정의 한다.

ManageBoard.contextTypes = {
    router: PropTypes.object.isRequired
}

callWrite 함수를 수정 한다.

callWrite(event) {
        event.preventDefault();

        this.props.actions.writeBoard(this.state.contents)
        .then(() => this.context.router.push('/about'))
        .catch(error => {
            console.log(error);
        })
    }

그리고 지난 포스팅에서 빼먹었던 propTypes도 추가 한다.

ManageBoard.propTypes = {
   contents: PropTypes.object.isRequired,
    actions: PropTypes.object.isRequired
}

여기까지 작성 하였다면 CREATE 기능 구현이 완료가 된것이다.

5번째 글은 필자가 직접 작성한 결과이다.

 

이번 포스팅에서는 redux에서 두번째 액션을 생성하고 이를 이용해서 CREATE 를

구현해 봤다.

다음 포스팅에서는 R에 해당되는 Read (읽기) 를 구현할 예정 이다.