Search

'REACT'에 해당되는 글 14건

  1. 2020.12.22 useContext
  2. 2020.12.22 useReducer
  3. 2020.12.21 useEffect
  4. 2020.12.21 useState
  5. 2020.12.20 connect
  6. 2020.12.17 react router
  7. 2020.12.16 redux
  8. 2020.12.13 scss
  9. 2020.12.13 webpack
  10. 2020.12.11 localStorage
  11. 2020.12.11 Props
  12. 2020.12.11 state
  13. 2020.12.06 babel
  14. 2020.12.06 arrow function

useContext

모바일/react 2020. 12. 22. 21:09 Posted by 아는 개발자

useContext를 사용하면 하위 컴포넌트에서도 상위 컴포넌트에서 전달하는 값을 공유 받을 수 있다. props를 통해서 전달하지 않고 동일한 Context를 넘겨 받은 인자를 통해서 공유가 가능하다. 이 함수를 이용해 state 값과 이를 업데이트 하는 dispatch 함수를 컴포넌트끼리 공유 할 수 있다.

 

1. Context 만들기 

 

하위 컴포넌트에서 공통적으로 공유할 수 있는 React Context를 만든다.

 

import React from 'react';

const NotesContext = React.createContext()

export { NotesContext as default }

 

2. Context 공유하기 

 

공유를 시작하려는 가장 상위 컴포넌트에서 태그를 씌워준다. value 안에 넣어둔 값들은 하위 컴포넌트에서 접근 할 수 있게 된다.

 

const NoteApp = () => {
  
    const [notes, dispatch] = useReducer(notesReducer, [])
  
    ...
  
    return (
      <NotesContext.Provider value={{ notes, dispatch }}>
        <h1>Notes</h1>
        <NoteList />
        <p>Add note</p>
        <AddNoteForm />
      </NotesContext.Provider>

 

3. 공유 데이터 접근 

 

하위 컴포넌트에서는 useContext 함수와 공통적으로 사용하고 있는 Context를 이용해 공유 데이터에 접근 할 수 있다. 아래 코드를 보면 useContext를 이용해 상위에서 공유하는 notes 인자를 접근하고 jsx로 만드는 형태다.

 

import React, { useContext } from 'react';
import Note from './Note';
import NotesContext from '../context/notes-context';

const NoteList = () => {
    const { notes } = useContext(NotesContext)

    return notes.map((note) => (
        <Note key={note.title} note={note} />
      ))
}

export { NoteList as default }
728x90

'모바일 > react' 카테고리의 다른 글

useContext  (0) 2020.12.22
useReducer  (0) 2020.12.22
useEffect  (0) 2020.12.21
useState  (0) 2020.12.21
connect  (0) 2020.12.20
react router  (0) 2020.12.17

useReducer

모바일/react 2020. 12. 22. 20:59 Posted by 아는 개발자

useReducer는 useState랑 비슷하나 state 업데이트 작업을 담당하는 reducer를 직접 넣어 줄 수 있다는 점이 다르다. 아래 코드에서 주석으로 처리된 useState 코드는 두번째 인자로 state 값을 업데이트 하는 작업을 일괄 담당했는데, useReducer를 사용하면 커스텀 reducer를 추가할 수 있어 action의 타입에 따라서 다른 행동을 취하도록 할 수 있다. 

 

useReducer도 useState처럼 리턴 값은 배열이며 첫번째 인자는 state 값이고 두번째 인자는 reducer에 액션을 보낼 수 있는 dispatch 함수다. 값을 업데이트 할 때는 dispatch 함수에 action 을 설정해서 업데이트 한다.

 

import React, { useEffect, useReducer } from 'react';
import notesReducer from '../reducers/notes';

const NoteApp = () => {
  
    // const [notes, setNotes] = useState([])
    const [notes, dispatch] = useReducer(notesReducer, [])
    
    
// 

const notesReducer = (state, action) => {
    switch (action.type) {
      case 'POPULATE_NOTES':
        return action.notes
      case 'ADD_NOTE':
        return [
          ...state,
          {
            title: action.title, body: action.body
          }
        ]
      case 'REMOVE_NOTE':
        return state.filter((note) => note.title !== action.title)
      default: 
        return state
    }
}

export { notesReducer as default }

 

아래는 Note 를 추가하고 제거하는 작업의 코드다. useState를 사용할 때는 setNote를 이용해서 바로 업데이트 하는 코드를 넣었다면 useReducer에 넣어둔 Reducer를 이용해 action 과 인자를 전달해서 작업을 넘길 수 있다. 액션을 추가하는 코드는 useReducer에서 받아온 dispatch 함수를 사용한다.

 

const addNote = (e) => {
  e.preventDefault()

  // setNotes([
  //   ...notes, 
  //    { title, body }
  // ])
  dispatch({
    type: 'ADD_NOTE',
    title,
    body
  })
}

const removeNote = (title) => {
  dispatch({
    type: 'REMOVE_NOTE',
    title
  })
  // setNotes(notes.filter((note) => note.title !== title))
}

 

useState는 간단한 상태값을 담당할 때 사용한다면 useReducer는 복잡한 상태 값, 중복되는 코드가 많이 생겨 일괄적으로 관리가 필요할 때 사용하면 좋을 것 같다.

728x90

'모바일 > react' 카테고리의 다른 글

useContext  (0) 2020.12.22
useReducer  (0) 2020.12.22
useEffect  (0) 2020.12.21
useState  (0) 2020.12.21
connect  (0) 2020.12.20
react router  (0) 2020.12.17

useEffect

모바일/react 2020. 12. 21. 20:27 Posted by 아는 개발자

리액트의 useEffect 라이브러리는 컴포넌트나 state에 변화가 생길 때 호출되는 함수다. 두개의 인자를 받는데 첫째 인자는 변경시 호출할 콜백함수고 두번째 인자는 상태를 변경을 감지할 state를 설정한다.  state를 별도로 설정하지 않으면 componentDidUpdate, componentDidMount랑 동일한 역할을 하게 된다. 

 

const NoteApp = () => {
  
  const [notes, setNotes] = useState([])
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')

  useEffect(() => {
    console.log('load data')
    const notesData = JSON.parse(localStorage.getItem('notes'))
    if (notesData) {
      setNotes(notesData)
    }
  }, [])

  useEffect(() => {
    console.log('update notes')
    const toJson = JSON.stringify(notes)
    localStorage.setItem('notes', toJson)
  }, [notes])

  useEffect(() => {
    console.log('useEffect called')
  })

 

위와 같이 여러개의 useEffect 함수를 둘 수 있다. 첫번째 useEffect에서는 두번째 인자에 빈 배열을 넣었는데 이러면 최초 한번만 호출되게 된다. componentDidMount 콜백과 기능이 유사하다. 두번째 useEffect 함수에서는 notes 상태 값을 인자로 두었다. notes 상태의 값이 변경될 때마다 함수가 호출된다. 세번째 useEffect 함수는 전달인자를 따로 넣지 않아서 내부에 어떤 state가 바뀌더라도 새롭게 호출된다. 

 

 

728x90

'모바일 > react' 카테고리의 다른 글

useContext  (0) 2020.12.22
useReducer  (0) 2020.12.22
useEffect  (0) 2020.12.21
useState  (0) 2020.12.21
connect  (0) 2020.12.20
react router  (0) 2020.12.17

useState

모바일/react 2020. 12. 21. 20:14 Posted by 아는 개발자

useState는 react 에서 비교적 최근에 나온 state 관리 라이브러리다. 기존에는 컴포넌트 생성할 때 state로 두고 싶은 변수들을 하나의 오브젝트로 관리했다면 useState 라이브러리를 사용해서 변수 별로 나눠서 선언할 수 있다. 

 

const NoteApp = () => {
  
  const [notes, setNotes] = useState([])
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')

 

useState 인자로 object를 받는데 이 값은 state의 초기 값이다. 배열, 정수형 인자, 문자열 모두 가능하다. 리턴 값으로는 길이가 2인 배열을 내놓는데 첫번째는 state 변수 값이고 두번째 값은 state 값을 변형 시킬 수 있는 setter 함수다. 

 

 const addNote = (e) => {
    e.preventDefault()
    setNotes([
      ...notes, 
       { title, body }
    ])
    setTitle('')
    setBody('')
  }

  const removeNote = (title) => {
    setNotes(notes.filter((note) => note.title !== title))
  }

 

기존에는 setState를 이용해서 모든 오브젝트를 다시 초기화해야 했다면 useState에서 넘어온 setter 함수를 이용해 내가 업데이트 하고 싶은 state만 명시적인 함수로 호출이 가능하기 때문에 관리가 한결 수월해진 측면이 있다. 한 컴포넌트 내에서 관리할 state 인자가 많아질수록 유용해질 기능인 것 같다.

 

728x90

'모바일 > react' 카테고리의 다른 글

useReducer  (0) 2020.12.22
useEffect  (0) 2020.12.21
useState  (0) 2020.12.21
connect  (0) 2020.12.20
react router  (0) 2020.12.17
redux  (0) 2020.12.16

connect

모바일/react 2020. 12. 20. 11:08 Posted by 아는 개발자

connect 함수는 리액트 앱의 하위 컴포넌트에서 redux store를 접근하는 것을 가능하게 해주는 역할을 한다. 이 함수를 이용해서 컴포넌트 단에서 redux store에 접근하고 액션을 호출 할 수 있게 된다. 이번 포스트에서는 간단한 예제로 connect 함수를 통해 redux store를 사용하는 방법을 다뤄보려고 한다.

 

0. 준비작업

 

connect 함수 소개를 위해 예제와 텍스트와 숫자를 담당하는 redux를 만들었다.

 

BlogStore.js

import { createStore, combineReducers } from 'redux';

const textReducerState = {
    text: '',
    name: 'textReducer'
};

const textReducer = (state = textReducerState, action) => {
    switch (action.type) {
        case 'SET_TEXT':
            return {
                ...state,
                text: action.text
            };
        default: 
            return state;
    }
}

const numberReducerState = {
    numberState: 30,
    name: 'numberReducer'
};

const numberReducer = (state = numberReducerState, action) => {
    switch (action.type) {
        case 'SET_NUMBER':
            return {
                ...state,
                number: action.number
            };
        default: 
            return state;
    }
};

export const configureStore = () => {
    const store = createStore(
        combineReducers({
            text: textReducer,
            number: numberReducer
        })
    );
    return store;
};

 

BlogActions.js

 

export const setText = (
    text = ''
) => ({
    type: 'SET_TEXT',
    text
});

export const setNumber = (
    number = 0
) => ({
    type: 'SET_NUMBER',
    number
});

 

 

1. Provider 

 

configureStore() 함수를 통해 store를 생성하고 Provider 태그에 store를 속성값으로 넣는다. 이러면 하위에 추가되는 component에서 redux store를 바라볼 수 있는 창구가 만들어진다.

 

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { configureStore } from './BlogStore';
import BlogMain from './BlogMain';

const store = configureStore();


const jsx = (
    <Provider store={store}>
        <BlogMain />
    </Provider>
);


ReactDOM.render(jsx, document.getElementById('app'));

 

2. connect 

 

하위 컴포넌트 단에서는 Provider에서 제공하는 store 함수를 connect 함수를 통해서 받아온다. 함수 형식이든 클래스 형식이든 받는 방식은 동일하다. 

 

 

2.1 클래스형식

 

import React from 'react';
import { connect } from 'react-redux';
import BlogDetail from './BlogDetail';


class BlogMain extends React.Component {
    render() {
        console.log(this.props.text)
        console.log(this.props.number)
        return (
            <div>
                <p>BlogMain component</p>
                <BlogDetail />
            </div>
        )
    };
};
const mapStateToProps = (state) => {
    return {
        text: state.text,
        number: state.number
    }
};
export default connect(mapStateToProps)(BlogMain);

 

클래스 형식 컴포넌트를 export 할 때 connect 함수를 사용하고 첫번째 인자에 mapStateToProps 함수를 넣었는데 redux store에 있는 값을 컴포넌트에 어떻게 넘겨줄지 세팅하는 작업이다.  넘겨 받은 값은 component의 props에 들어가서 호출 할 수 있다. 아래 사진은 render() 함수 안에서 console로 찍은 로그다. textReducer와 numberReducer가 출력되는 것을 볼 수 있다.

 

 

2.2 함수 형식 

 

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

const BlogDetail = (props) => (
    <div>
        <p>BlogTextDetail</p>
        <p>{props.text.name}</p>
    </div>
);
const mapStateToProps = (state) => {
    return {
        text: state.text
    };
};

export default connect(mapStateToProps)(BlogDetail)

 

함수 형식도 크게 다르지 않다. 컴포넌트 내에서 호출 할 때 this를 부르지 않아도 된다는 점만 다르다. 위 코드로 호출하면 아래 그림처럼 화면 뷰가 그려진다.

 

 

3. Action 

 

connect로 컴포넌트에 전달 할 때 store만 전달 하는것이 아니라 action을 넣을 수 있는 dispatch 함수까지 전달된다. react 디바이스 툴을 사용해보면 component의 props 안에 dispatch가 들어있는 것을 확인 할 수 있다. 

 

 

실제로도 잘 사용할 수 있을 지 테스트 해보자. 방금 전에 사용한 BlogDetail 컴포넌트를 살짝 수정해서 현재 store에 저장된 text를 출력하고 버튼을 추가하고 클릭하면 text를 BlogDetail로 바뀌도록 했다.

 

import React from 'react';
import { connect } from 'react-redux';
import { setText } from './BlogActions';

const BlogDetail = (props) => (
    <div>
        <p>BlogTextDetail</p>
        <p>current store text value: {props.text.text}</p>
        <button onClick={() => {
            props.dispatch(setText('BlogDetail'))
        }}>Change text to BlogDetail</button>
    </div>
);

const mapStateToProps = (state) => {
    return { text: state.text};
};

export default connect(mapStateToProps)(BlogDetail)

 

함수를 실행하고 버튼을 클릭하니 화면이 아래와 같이 store의 text 값이 BlogDetail로 변경됐다.

 

 

4. 총평 

 

코딩을 처음 하는 분이면 이걸 왜 이렇게까지 해야할지 이해가 안될 수 있을 것 같은데 이전에 mvvm, mvc 패턴을 경험해본 개발자들에게는 redux가 크게 어려울 것 같지 않다. 강의 들을 때는 헷갈렸는데 실제로 코드로 짜보니까 어떤 식으로 구조를 잡아야할 지 느낌이 온다. 물론 자바스크립트 언어 특성상 state 세부 이름을 관리할 때 꽤 귀찮음을 겪을 것 같긴 하다.

728x90

'모바일 > react' 카테고리의 다른 글

useEffect  (0) 2020.12.21
useState  (0) 2020.12.21
connect  (0) 2020.12.20
react router  (0) 2020.12.17
redux  (0) 2020.12.16
scss  (0) 2020.12.13

react router

모바일/react 2020. 12. 17. 19:52 Posted by 아는 개발자

react 에서는 react-router-dom 라이브러리를 통해  들어 오는 주소 별로 별도의 페이지를 보여줄 수 있는 라우팅 기능을 제공한다. 리액트의 특성에 맞게 이 라이브러리는 어떤 페이지로 진입 했을 때 어떤 페이지를 보여 줄 것인지를 컴포넌트 단위로 뽑을 수 있다.

 

1. 라이브러리 임포트 

 

리액트와 필요한 라이브러리를 임포트 한다.

 

import React from 'react';
import { BrowserRouter, Route, Switch, Link, NavLink } from 'react-router-dom';

 

2. Route

 

const AppRouterExample = () => (
    <BrowserRouter>
        <div>
            <Switch>
                <Route path="/" component={() => (<h2>This is DashboardPage</h2>)} exact={true} />
                <Route path="/create" component={() => (<h2>This is Create Page</h2>)} exact={false} />
                <Route path="/edit/:id" 
                    component={ (props) => (<h2>This is Edit Page {props.match.params.id}</h2>)} 
                        exact={true} />
                <Route path="/help" 
                    component={() => (<h2>This is help page</h2>)} 
                    exact={true} />
                <Route component={() => (<h2>This is not 404 page</h2>)} />
            </Switch>
        </div>
    </BrowserRouter>
);

 

<BrowserRouter> 와 <Switch> 태그 내에 위치한 <Route> 태그로 관리하고 싶은 경로를 설정할 수 있다. 이렇게 두면 애플리케이션이 관리하는 경로를 설정 할 수 있게 된다.

 

2.1 path 

 

라우팅할 경로를 정의하는 값이다. 위 페이지에서는 /create, /edit, /help 페이지를 경로로 뒀다. edit 페이지의 경우에는 수정하려는 데이터의 id를 인자로 받을 수 있고 이 값은 component에 전달된다. component 객체에 props로 전달되며 저장되는 필드는 컴포넌트에 있는 값과 같다.

 

2.2 component 

 

해당 경로로 들어올 경우 어떤 component를 보여줄 것인지를 결정하는 곳이다. 직접 컴포넌트를 만들어서 넣을 수 있으며 이 예제에서는 component 필드 내에서 보여줄 수 있는 값을 넣었다. /edit 경로를 보면 props로 Route로부터 인자를 받아오는데 /edit에서 받아오는 id 정보를 확인 할 수 있다.

 

2.3 exact 

 

exact는 이 경로를 명확하게 볼 것인지 말것인지를 설정한다. 평소 익히 쓰던 path와 다른 개념이라 와닿지 않을 것 같은데 exact값이 false면 앞에 부분만 맞아도 해당 페이지로 렌딩이 된다. 예로 /create 는 exact 값이 false이기 때문에 /create/34 로 접근하든, /create/edit 으로 접근하든 모두 create 페이지로 렌딩해준다.

 

3. NavLink 

 

const AppRouterExample = () => (
    <BrowserRouter>
        <div>
            <div>
                <h1>This is Header</h1>
                <NavLink to="/" activeClassName="is-active" exact={true}>Dashboard</NavLink>
                <NavLink to="/create" activeClassName="is-active">Create Expense</NavLink>
                <NavLink to="/edit" activeClassName="is-active">Edit Expense</NavLink>
                <NavLink to="/help" activeClassName="is-active">Help</NavLink>
            </div>

 

NavLink는 하이퍼링크 기능이고 스타일링을 가능하게 한다. 내부에 있는 필드 값을 바꿔서 더 링크를 더 이쁘게 만들 수 있다.

728x90

'모바일 > react' 카테고리의 다른 글

useState  (0) 2020.12.21
connect  (0) 2020.12.20
react router  (0) 2020.12.17
redux  (0) 2020.12.16
scss  (0) 2020.12.13
webpack  (0) 2020.12.13

redux

모바일/react 2020. 12. 16. 20:28 Posted by 아는 개발자

react는 state를 이용해서 컴포넌트의 상태를 관리하는데 state 하나에 들어가는 element가 많아질수록 관리하기가 힘들어지는 문제가 있다. 그래서 react에서는 redux라는 라이브러리를 이용해서 state를 좀더 쉽게 관리할 수 있게 해줬다. 크게 state를 관리하는 store와 store 를 변경하려는 dispatch 그리고 변경 작업을 일괄 관리하는 reducer로 나뉘는데 이번 포스트에서는 각각에 대해서 간단히만 다뤄보려고 한다.

 

1. createStore 

 

redux로 관리할 state 집합을 만드는 작업이다. 함수의 인자로는 reducer를 받는다. 

 

const store = createStore(countReducer);

 

2. action 

 

state를 바꾸기 위해 취하는 액션이다. 단 여기에는 액션이 들어가지 않고 액션에 필요한 데이터만 들어간다. 변수 이름을 자유롭게 입력할 수 있는데 type 필드에 액션의 종류를 정해주는게 일반적인 것 같다. dispatch 함수를 통해 액션을 실행 할 수 있다.

 

const incrementCount = ({incrementBy = 1} = {}) => ({
    type: 'INCREMENT',
    incrementBy
});

store.dispatch(incrementCount())

 

3. reducer 

 

액션을 대신 처리해주는 부분이다. MVC로 치면 controller에 해당하는 부분으로 실제 state 값의 변경을 담당한다. reducer에서 state에 대한 변경을 일괄적으로 담당하기 때문에 관리하기가 한결 쉬워지는 장점이 있다.

 

// Reducer
// 1. Reducers are pure functions
// 2. Never change state or action 

const countReducer = (state = { count: 0 }, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return {
                count: state.count + action.incrementBy
            };
        default:
            return state;
    }
};

 

4. subscribe 

 

store의 subscribe 함수로 state 변경에 대한 변화를 구독 할 수 있다. reducer에서 업데이트 값들은 모두 여기를 거치게 된다. state 변경 값을 화면에 노출해야하는 경우에는 이 함수를 사용하면 된다.

 

store.subscribe(() => {
    console.log(store.getState());
});
728x90

'모바일 > react' 카테고리의 다른 글

connect  (0) 2020.12.20
react router  (0) 2020.12.17
redux  (0) 2020.12.16
scss  (0) 2020.12.13
webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11

scss

모바일/react 2020. 12. 13. 15:50 Posted by 아는 개발자

Syntactically Awesome StylesheetS 의 준말로 기존 css보더 더 편하게 스타일링 할 수 있는 언어다. css에 있는 모든 기능을 포함하고 여기에 더해 변수랑 내부에서 제공하는 함수도 사용할 수 있기 때문에 개발자들의 반복적인 작업을 확 줄여준다. 5년 전에 간단히 홈페이지 만들면서 css를 쓰고 불편하다고 느낀후 지금까지 손댄적이 없었는데 지금은 scss 라는 언어로 더 쉽게 스타일링 할 수 있게 된 것 같다. 이번포스트에서는 scss를 react에 적용하는 방법을 간단히 소개한다.

 

1. scss 로더 추가 

 

scss는 확장 기능이므로 새로 css로 transformation 해주는 기능이 필요하다. 별도의 로더를 설치하고 스크립트를 실행할 수 있으나 여기선 webpack에 로더를 추가해서 정리하려고 한다. 먼저 아래 명령어로 필요한 라이브러리를 추가한다.

 

yarn add style-loader css-loader sass-loader node-sass

 

그리고 webpack.config.js에 css, scss 용 로더를 추가한다.

 

module.exports = {
    ...
    module: {
        rules: [{
            loader: 'babel-loader',
            test: /\.js$/,
            exclude: /node_modules/
        }, {
            test: /\.s?css$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader'
            ]

 

2. scss 파일 추가 

 

scss로 쓸 파일을 추가한다. scss 언어 내에 import 기능이 있어 여러 개의 파일로 의존성이 가능하다. 최상위 파일로 styles.scss 을 만들고 예시로 base 폴더 내에 base.scss 파일을 추가한다.

 

styles.scss

 

@import './base/base';

 

base.scss

 

간단하게 브라우저 전체에 적용될 수 있는 스타일링을 넣었다.

 

body {
    background: $dark-blue;
    font-family: Helvetica, Arial, sans-serif;
    font-size: 2.4rem;
}

 

3. entry 파일에서 임포트 

 

entry에 해당하는 파일에서 아까 추가한 scss 파일을 임포트 한후 간단한 코드를 넣어 봤다.

 

import React from 'react';
import ReactDOM from 'react-dom';
import './styles/styles.scss';

ReactDOM.render(<div><h1>This is selfish-developer blog</h1></div>, document.getElementById('app'))

 

그 결과 아래처럼 스타일링이 된 것을 확인 할 수 있다.

 

728x90

'모바일 > react' 카테고리의 다른 글

react router  (0) 2020.12.17
redux  (0) 2020.12.16
scss  (0) 2020.12.13
webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
TAG CSS, REACT, scss

webpack

모바일/react 2020. 12. 13. 15:10 Posted by 아는 개발자

webpack 은 자바스크립트로 짠 애플리케이션의 모듈 관리용 툴이다. 애플리케이션에서 필요한 모듈의 의존성을 관리하고 프로젝트용 코드를 만들어준다. 예로 리액트 자바스크립트에서 필요한 babel, style-loader, css-loader 같은 스타일용 로더, 애플리케이션의 시작위치를 정하는 entry, 디버깅용 devtool 설정, 서버 관리까지 모두 webpack을 이용해서 관리가 가능하다. 짜치는 일들을 하나로 묶어서 관리해주는 라이브러리니 배워두면 프로젝트 관리할 때 크게 도움이 될 것 같다.

 

1. Configuration

 

webpack.config.js 파일을 통해서 webpack에서 관리하고 싶은 설정을 추가할 수 있다. 아래 코드는 튜토리얼 프로젝트에서 추가한 webpack 설정 코드다. 공식 문서를 살펴보면 더 많은 설정을 추가 할 수 있다. 이번 포스트에서는 주요 설정에 대해서만 정리하려고 한다.

 

module.exports = {
    entry: './src/app.js',
    output: {
        path: path.join(__dirname,'public'),
        filename: 'bundle.js'
    },
    module: {
        rules: [{
            loader: 'babel-loader',
            test: /\.js$/,
            exclude: /node_modules/
        }, {
            test: /\.s?css$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader'
            ]
        }]
    },
    devtool: 'cheap-module-eval-source-map',
    devServer: {
        contentBase: path.join(__dirname,'public')
    }
};

 

1.1 Entry 

 

webpack이 어디에서 의존성 그래프를 그려갈 지 설정하는 곳이다. 어디서부터 프로그램을 시작할지 설정하는 작업이라고 봐도 좋다. c언어 프로그램으로 치면 main함수를 어디에 둘 지 설정하는 작업이라고 봐도 될 것 같다. 위 소스코드에서는 src 폴더에 있는 app.js를 시작점으로 두었다.

 

1.2 Output 

 

webpack으로 만든 묶음(bundle)을 어디에 생성할 것인지를 설정한다. 일단 c언어라면 컴파일후 바이너리 결과물을 어디에 둘 것인지 설정하는 것과 같다.

 

1.3 Loaders

 

webpack 이 어떤 타입의 파일을 특정한 모듈로 변경하고 의존성 그래프에 추가할지를 설정하는 작업이다. 위 코드의 module 내부를 보면 test 속성과 use 속성이 있는데 test는 어떤 파일을 변형할 것인지를 설정하고 use는 어떤 loader를 사용할 것인지 설정한다. 여기서 test는 파일을 설정하는 작업이라고 했는데 파일 이름을 정규표현식으로 정하고 있다. 위 코드에서는 jsx 컨버팅용 babel-loader와 css 스타일링용 style-loader, css-loader, sass-loader 를 추가했다.

 

1.4 DevServer 

 

webpack-dev-server 라이브러리를 이용해 빠르게 프로그램을 시작 할 수 있는 기능이다. devServer 값을 설정하면 리액트 프로그램을 시작 하는 주소나 포트번호 같은 값을 쉽게 설정 할 수 있다. 위 코드에서는 가장 기본인 시작 위치만 설정 했다.

 

2. 설치 및 사용

 

2.1 설치 

 

npm을 이용해 global 하게 설치하는 방법도 있지만 꼬여버리면 답이 없으므로 프로젝트 단위로 yarn을 이용해서 설치한다. 

 

yarn add webpack webpack-dev-server

 

2.2 스크립트 파일 추가 

 

package.json에 스크립트 코드를 추가한다

 

{
  "name": "knowing-developer",
  ...
  "scripts": {
    "build": "webpack",
    "dev-server": "webpack-dev-server"
  },

 

build 스크립트는 webpack을 이용해 프로젝트 파일을 변경 시켜주는 스크립트다. 로컬에 서버까지 만드려면 dev-server 스크립트까지 추가한다.

 

2.3 실행 

 

yarn run dev-server

 

방금 추가한 스크립트를 실행한다.

728x90

'모바일 > react' 카테고리의 다른 글

redux  (0) 2020.12.16
scss  (0) 2020.12.13
webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
state  (0) 2020.12.11

localStorage

모바일/react 2020. 12. 11. 18:00 Posted by 아는 개발자

 

리액트의 localStorage는  Android의 SharedPreference나 iOS의 UserDefaults 처럼 애플리케이션 단위로 key-value 값을 저장할 수 있는 라이브러리다. 아래 코드를 보면 getItem 함수에 key값을 넣어서 값을 받아오고 setItem 함수에 key 값을 넣어서 값을 업데이트한다. 

 

아래 코드를 보면 JSON 라이브러리를 사용해 변환하는 과정이 있는데 이 이유는 localStorage에서는 string의 형태로만 저장이 가능하기 때문이다. 그래서 일반 텍스트를 사용하는 것이 아니면 모두 JSON을 이용해 값을 변환해서 저장해야한다. 배열 같은 값을 저장한다면 어차피 변환하는 과정이 필요하기 때문에 항상 써두는 것도 나쁘지 않을 것 같다.

 

class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleIncrease = this.handleIncrease.bind(this)
        this.handleDecrease = this.handleDecrease.bind(this)


        this.state = {
            counter: 0
        };
    }

    componentDidMount() {
        const json = localStorage.getItem('counter');
        const counter = JSON.parse(json);
        
        if (counter) {
            this.setState((prevState) => {return {counter: counter}})
        }
    }

    componentDidUpdate(prevProps, prevState) {
        const json = JSON.stringify(this.state.counter);
        localStorage.setItem('counter', json)
    }

 

componentDidMount() 와 componentDidUpdate() 함수는 리액트의 라이프사이클 관리 함수다. componentDidMount()는 리액트 컴포넌트가 처음 생성 될 때 호출되고 componentDidUpdate는 리액트 컴포넌트에 변화가 생겼을 때, 예로 state 값이 변화해서 UI가 바뀌었을 때 호출된다. 위 코드는 각 라이프 사이클에서 필요한 작업을 넣은 것이다. 주로 componentDidMount에서 기존 값을 가져오고(fetch) componentDidUpdate에서 값을 업데이트 한다

 

소스코드

 

https://github.com/kwony/react-study/blob/main/src/playground/blog-localstorage.js

728x90

'모바일 > react' 카테고리의 다른 글

scss  (0) 2020.12.13
webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
state  (0) 2020.12.11
babel  (0) 2020.12.06

Props

모바일/react 2020. 12. 11. 18:00 Posted by 아는 개발자

props는 리액트에서 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달 할 때 사용하는 기능이다. 아래 그림처럼 Header가 App 안에 포함되어 있을 때 App에서 Header에게 title과 subtitle을 전달하게 되는데 이를 props를 이용해서 할 수 있다.

 

 

1. 데이터 전달

 

class App extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        const title = '아는개발자'
        const subtitle = '리액트를 공부해봅시다'
        return (
            <div>
                <Header title={title} subtitle={subtitle} />
            </div>
        )
    }
}

 

상위 컴포넌트의 render() 함수에서 하위 컴포넌트를 리턴할 때 내부에 key와 value로 전달한다. Header 컴포넌트에 subtitle로 전달하고 있다. key 값은 자유롭게 설정할 수 있고 받는 곳에서 동일한 key 값으로만 받아오면 된다.

 

2. 데이터 받아오기 

 

class Header extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return(
            <div>
                <h1>{this.props.title}</h1>
                <h2>{this.props.subtitle}</h2>
            </div>
        )        
    }
}

 

상위로부터 받아온 props 데이터를 확인해본다. props 데이터는 {this.props} 내에 있고 상위에서 보내준 key 값에 따라서 값을 확인 할 수 있다.

 

3. stateless function 

 

함수의 형태에서도 props로 전달된 값을 받아 올 수 있다. 아래 코드에선 props 변수를 받는 함수를 만들고 return 값으로 props에서 받아온 이름으로 버튼을 만들었다. 상위 컴포넌트인 App에서는 Action 컴포넌트에 buttonName을 props로 전달했다. 

 

const Action = (props) => {
    return (
        <div>
            <button>
                {props.buttonName}
            </button>
        </div>
    )
}

class App extends React.Component {
    ...
    render() {
    ...
                <Action buttonName={'click'} />
            </div>
        )
    }
}

 

4. 함수 전달

 

props로 데이터 뿐만 아니라 함수도 전달 할 수 있다. App 컴포넌트에 알럿 메시지를 띄우는 handleClick이라는 함수를 만들고 생성자에서 바인딩을 한 다음 Action 컴포넌트에 데이터를 전달하는 것과 동일하게 함수를 전달한다. 버튼을 그리는 Action 함수에서는 button 의 버튼 클릭 콜백함수에 받아온 handleClick을 인자로 넣는다. 

 

class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
        alert('button clicked');
    }

    render() {
        const title = '아는개발자'
        const subtitle = '리액트를 공부해봅시다'
        const buttonName = 'click'
        return (
            <div>
                <Header title={title} subtitle={subtitle} />
                <Action buttonName={buttonName} handleClick={this.handleClick} />
            </div>
        )
    }
}

const Action = (props) => {
    return (
        <div>
            <button onClick={props.handleClick}>
                {props.buttonName}
            </button>
        </div>
    )
}

 

테스트 결과 버튼을 클릭하면 App에서 설정한 알럿 메시지가 띄워지는것을 확인 할 수 있다.

 

 

5. 소스코드

 

https://github.com/kwony/react-study/blob/main/indecision-app/src/playground/blog-props.js

728x90

'모바일 > react' 카테고리의 다른 글

webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
state  (0) 2020.12.11
babel  (0) 2020.12.06
arrow function  (0) 2020.12.06
TAG Props, REACT

state

모바일/react 2020. 12. 11. 18:00 Posted by 아는 개발자

state는 리액트 컴포넌트 내에서 사용할 변수를 관리하는 역할을 한다. 예로 간단하게 정수 값을 표시하고 1씩 증가시키고 감소시키는 버튼이 있다고 하자. 아래와 같은 기능을 제공하는 앱이라면 컴포넌트중 누군가는 현재 화면에 표시되는 값을 들고 있어야 한다.

 

1. state 관리

 

이 값은 컴포넌트내의 state 변수에서 관리한다. 아래 코드를 보면 App 컴포넌트의 생성자에서 state를 만들고 그 안에 counter라는 값을 초기화 하는 것을 볼 수 있다. 그리고 render() 함수에서 현재 state 값을 참조해 counter 값을 보여주고 있다.

 

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0
        };
    }

    render() {
        const title = '아는개발자'
        const subtitle = '이번에는 state를 공부해봅시다'
        const incrButton = '+1'
        const decrButton = '-1'
        return (
            <div>
                <Header title={title} subtitle={subtitle} />
                <Action buttonName={incrButton} />
                <Action buttonName={decrButton} />
                <p>현재 값: {this.state.counter}</p>
            </div>
        )
    }
}

 

2. state 변경 

 

state 값을 업데이트 할 때는 constructor 함수에서 처럼 this.state 값에 직접 업데이트 하는게 아니라 setState 함수를 사용한다. state 값이 업데이트 되면서 이 값을 참조하고 있는 ui도 동적으로 업데이트하기 위해서다. 이렇게 하지 않으면 state 값만 바뀌고 실제 화면은 그대로 남게된다. 

 

class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleIncrease = this.handleIncrease.bind(this)
        this.handleDecrease = this.handleDecrease.bind(this)
        this.state = {
            counter: 0
        };
    }

    handleIncrease() {
        this.setState((prevState) => ({
            counter: prevState.counter + 1
        }))
    }
    handleDecrease() {
        this.setState((prevState) => {return {counter: prevState.counter - 1}})
    }

    render() {
        ...
        const incrButton = '+1'
        const decrButton = '-1'
        return (
            <div>
                ...
                <Action buttonName={incrButton} handleClick={this.handleIncrease} />
                <Action buttonName={decrButton} handleClick={this.handleDecrease} />
                <p>현재 값: {this.state.counter}</p>
            </div>
        )
    }

 

handleIncrease 함수와 handleDecrease 함수에서 setState 내부 구현부를 살짝 다르게 했다. handleIncrease처럼 간단하게 값을 업데이트할 수도 있고 handleDecrease처럼 return까지 포함해서 값을 업데이트 할 수도 있다.

 

3. 소스코드

https://github.com/kwony/react-study/blob/main/src/playground/blog-state.js

 

728x90

'모바일 > react' 카테고리의 다른 글

webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
state  (0) 2020.12.11
babel  (0) 2020.12.06
arrow function  (0) 2020.12.06
TAG REACT, State

babel

모바일/react 2020. 12. 6. 14:12 Posted by 아는 개발자

babel은 JFX로 작성된 react javascript 파일을 브라우저에서 인식할 수 있도록 변경해주는 컴파일러다. 예시로 아래처럼 생긴 코드를 브라우저에 렌더링 하려고 하면

 

const appRoot = document.getElementById('app');

function renderApp() {
    // JSX - JavaScript XML 
    var template = <div>
        <p>Hello react</p>
    </div>

    var appRoot = document.getElementById('app');
    ReactDOM.render(template, appRoot);
 }
 renderApp()

 

요런 에러가뜬다.

 

이건 JFX로 작성된 형태를 브라우저에서 읽을 수 없기 때문이다. react에서 기본적으로 만들어주는 프로젝트를 사용하면 이런 에러가 뜨지 않는데 처음부터 만들어가면 요런 에러를 보게 된다. babel 라이브러리를 이용하면 JFX로 작성한 언어를 컴파일해서 브라우저가 읽을 수 있는 형태로 바꿀 수 있다.

 

먼저 아래 명령어를 사용해서 babel을 설치한다.

 

npm install babel-cli

 

아래 명령어로 컴파일을 할 수 있다. 이 명령어의 뜻은 source 파일에 있는 build-it-visible.js 라는 파일을 babel로 컴파일해서 결과물을 public/scripts/app.js에 입력하라는 뜻이다. presets 옵션은 컴파일 옵션이고, watch는 build-it-visible.js 파일의 변화를 계속 관찰하겠다는 뜻이다. 저장하면 자동으로 컴파일을 해주므로 유용하다.

 

babel src/build-it-visible.js --out-file=public/scripts/app.js --presets=env,react --watch

 

그래서 아까 파일을 babel로 컴파일해주면 요렇게 바뀌게 된다.

 

'use strict';

var appRoot = document.getElementById('app');

function renderApp() {
    // JSX - JavaScript XML 
    var template = React.createElement(
        'div',
        null,
        React.createElement(
            'p',
            null,
            'Hello react'
        )
    );

    var appRoot = document.getElementById('app');
    ReactDOM.render(template, appRoot);
}
renderApp();

 

그리고 브라우저에서는 요렇게 잘 뜨게 된다.

 

 

사실 Babel은 인터프리터로 봐야한다.

728x90

'모바일 > react' 카테고리의 다른 글

webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
state  (0) 2020.12.11
babel  (0) 2020.12.06
arrow function  (0) 2020.12.06

arrow function

모바일/react 2020. 12. 6. 13:59 Posted by 아는 개발자

요즘 트렌드 언어 답게 react에서 사용하는 javascript도 arrow function으로 함수를 줄일 수 있다. 자바에서 사용하는 람다나 swift의 closure 랑 비슷하게 이름없는 함수(anonymous) 를 사용해서 1회성의 함수를 따로 선언하지 않고 삽입해서 쓸 수 있는 기능이다.

 

이 함수들은 모양새는 다르지만 모두 똑같이 제곱값을 리턴하는 함수다.

 

const square1 = function(x) {
    return x * x
};

const square2 = (x) => {
    return x * x;
};

const square3 = (x) => x * x;

 

객체 내에서 함수로 들어갈 때도 동일하게 줄일 수 있다. 

 

const user = {
    name: 'kwony',
    cities: ['pangyo', 'sinchon', 'madrid'],
    printPlacedLived: function() {
        return this.cities.map((city) => {
            return this.name + ' has lived in ' + city + '!';
        });
    },

    printPlacedLived2() {
        return this.cities.map((city) => {
            return this.name + ' has lived in ' + city + '!';
        });
    }
}

 

view 요소의 콜백 함수에도 arrow function을 적용할 수 있다. 아래 코드보면 첫번째 버튼은 arrow function을 적용해서 넣었고 두번째 버튼은 따로 만든 onClickButton 함수를 사용했다. 두개 모두 동일한 역할을 한다.

 

const onClickButton = () => {
    toggle.isVisible = !toggle.isVisible
    render()
}

const render = () => {
    const template = (
        <div>
        <button onClick={() => {
            toggle.isVisible = !toggle.isVisible
            render()
        }}>{toggle.isVisible ? 'hide detail' : 'show detail'}</button>
        <button onClick={onClickButton}>{toggle.isVisible ? 'hide detail' : 'show detail'}</button>

 

간단해보이지만 손에 익으려면 꽤 시간이 걸리니 이것도 놓치지 말고 꼼꼼히 연습해봐야겠다.

728x90

'모바일 > react' 카테고리의 다른 글

webpack  (0) 2020.12.13
localStorage  (0) 2020.12.11
Props  (0) 2020.12.11
state  (0) 2020.12.11
babel  (0) 2020.12.06
arrow function  (0) 2020.12.06