728x90
반응형

전 글에서 설명할 때 

 

1. 상위 컴포넌트에서 내보내고,

export const UserDispatch = React.createContext(null);

 

 

 

2. 감싸고,

  return (
    <UserDispatch.Provider value={dispatch}>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : {count}</div>
    </UserDispatch.Provider>
  );

 

 

 

 

3. 하위 컴포넌트에서 import 하고,

import { UserDispatch } from './App';

 

 

4. 하위 컴포넌트에서 useContext로 가져왔다.

const User = React.memo(function User({ user }) {
  const dispatch = useContext(UserDispatch);

 

 

 

 

이 방법이 잘못된건 아니지만, 다른 방법도 있어서 설명하겠다.

 

const TodoStateContext = createContext();
const TodoDispatchContext = createContext();

export function TodoProvider({ children }) {
  const [state, dispatch] = useReducer(todoReducer, initialTodos);
  return (
    <TodoStateContext.Provider value={state}>
      <TodoDispatchContext.Provider value={dispatch}>
        {children}
      </TodoDispatchContext.Provider>
    </TodoStateContext.Provider>
  );
}

export function useTodoState() {
  return useContext(TodoStateContext);
}

export function useTodoDispatch() {
  return useContext(TodoDispatchContext);
}

먼저 상위 컴포넌트에서 위 코드가 같이 선언해준다.

 

 

 

1. 먼저 state 와 dispatch가 담길 Context를 선언해준다.

const TodoStateContext = createContext();
const TodoDispatchContext = createContext();

 

 

2. 그 다음 다른 컴포넌트에서 import 할 함수들을 정의한다.

export function useTodoState() {
  return useContext(TodoStateContext);
}

export function useTodoDispatch() {
  return useContext(TodoDispatchContext);
}

 

 

3. 그 다음 Context를 사용 할 하위 컴포넌트들을 감싼다

export function TodoProvider({ children }) {
  const [state, dispatch] = useReducer(todoReducer, initialTodos);
  return (
    <TodoStateContext.Provider value={state}>
      <TodoDispatchContext.Provider value={dispatch}>
        {children}
      </TodoDispatchContext.Provider>
    </TodoStateContext.Provider>
  );
}

 

 

4. 그 다음 하위 컴포넌트에서 import하여 사용한다.

import React from 'react';
import { useTodoState, useTodoDispatch } from '../TodoContext';

function Sample() {
  const state = useTodoState();
  const dispatch = useTodoDispatch();
  return <div>Sample</div>;
}

 

 

차이점은

- useContext를 하위컴포넌트에서 사용하냐, 

- useContext를 상위컴포넌트에서 사용하여 Context가 return되는 함수를 정의하고 하위 컴포넌트에서 이 함수를 하위

   컴포넌트에서 사용하냐 이다.

 

사용하기 나름이라 편한걸로 쓰면 될 것 같다.

 

 

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | API 연동 | 기본  (0) 2021.10.07
React.js | 입문 | Immer  (0) 2021.09.17
React.js | 입문 | Context API 전역 값 관리(1)  (0) 2021.09.17
React.js | 입문 | React.memo  (0) 2021.09.17
React.js | 입문 | useCallback  (0) 2021.09.17
728x90
반응형

우리가 현재 만들고 있는 프로젝트를 보면, App 컴포넌트에서 onToggle, onRemove 가 구현이 되어있고 이 함수들은 UserList 컴포넌트를 거쳐서 각 User 컴포넌트들에게 전달이 되고 있다.

 

컴포넌트들이 상위 컴포넌트에서 하위컴포넌트로 전달되어지는 방법이다.

 

상위컴포넌트에서 함수들이 전달되어질 때, 거쳐야 할 컴포넌트가 여러개 ( 즉 하위 컴포넌트의 하위 컴포넌트의 ... )가

되면 매우 번거로운 작업이 될 것이다.

 

이 때 리액트의 Context API 와 이전 섹션에서 배웠던 dispatch 를 함께 사용하면 이러한 복잡한 구조를 해결 할 수 있다.

 

먼저 이렇게 React.createContext() 라는 함수를 사용한다.

const UserDispatch = React.createContext(null);

 

 

이러면 Context의 기본 값을 설정해줄 수 있다. 위에서 설정한 값은 따로 값을 사용하지 않았을 때의 기본 값이다.

 

Context를 만들면 Context안에 Provider 라는 컴포넌트가 들어있는데, 이 컴포넌트를 통해 Context의 값을 지정해줄 수

있다. value라는 값을 설정해주면 된다.

<UserDispatch.Provider value={dispatch}>...</UserDispatch.Provider>

 

아래 전체 코드를 보면서 이해해보자.

 

App.js

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
import useInputs from './hooks/useInputs';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

const initialState = {
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]
};

function reducer(state, action) {
  switch (action.type) {
    case 'CREATE_USER':
      return {
        users: state.users.concat(action.user)
      };
    case 'TOGGLE_USER':
      return {
        ...state,
        users: state.users.map(user =>
          user.id === action.id ? { ...user, active: !user.active } : user
        )
      };
    case 'REMOVE_USER':
      return {
        ...state,
        users: state.users.filter(user => user.id !== action.id)
      };
    default:
      return state;
  }
}

// UserDispatch 라는 이름으로 내보내줍니다.
export const UserDispatch = React.createContext(null);

function App() {
  const [{ username, email }, onChange, onReset] = useInputs({
    username: '',
    email: ''
  });
  const [state, dispatch] = useReducer(reducer, initialState);
  const nextId = useRef(4);

  const { users } = state;

  const onCreate = useCallback(() => {
    dispatch({
      type: 'CREATE_USER',
      user: {
        id: nextId.current,
        username,
        email
      }
    });
    onReset();
    nextId.current += 1;
  }, [username, email, onReset]);

  const onToggle = useCallback(id => {
    dispatch({
      type: 'TOGGLE_USER',
      id
    });
  }, []);

  const onRemove = useCallback(id => {
    dispatch({
      type: 'REMOVE_USER',
      id
    });
  }, []);

  const count = useMemo(() => countActiveUsers(users), [users]);
  return (
    <UserDispatch.Provider value={dispatch}>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : {count}</div>
    </UserDispatch.Provider>
  );
}

export default App;

 

 

위에서 말했듯이 React.createContext 함수로 내보냈고,

 

    <UserDispatch.Provider value={dispatch}>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : {count}</div>
    </UserDispatch.Provider>

이런 식으로 컴포넌트들을 .Provider에 감싸고, value로 Context의 값을 지정해주었다.

 

 

그 다음 감싼 컴포넌트 내에서 먼저 import를 해주고,

import { UserDispatch } from './App';

 

 

아래와 같이 useContext를 사용하여 불러왔던 UserDispatch를 사용하게끔 설정해주면 끝!!

const User = React.memo(function User({ user }) {
  const dispatch = useContext(UserDispatch);

 

 

이제 우리는 여러 컴포넌트를 거쳐서 전달할 필요없이 최상위 폴더에서 React.createContext 함수를 써서 내보내고,

Provider로 하위 컴포넌트를 감싼다음에 사용할 필요가 있을 때 useContext로 편하게 불러올 수 있다!

 

 

참고로 React.createContext를 안쓰고

import React, { useReducer, createContext } from 'react';

이런식으로 불러와도 된다.

 

 

참조 

http://react.vlpt.us/basic/22-context-dispatch.html

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | Immer  (0) 2021.09.17
React.js | 입문 | Context API 전역 값 관리(2)  (0) 2021.09.17
React.js | 입문 | React.memo  (0) 2021.09.17
React.js | 입문 | useCallback  (0) 2021.09.17
React.js | 입문 | 커스텀 Hook  (0) 2021.09.17
728x90
반응형

useMemo와 비슷한 useCallback이다. 

 

  const onCreate = useCallback(() => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  }, [users, username, email]);

 

 

useCallback 첫번째 파라미터에 연산내용이 담긴 함수를 정의하고, 두번째 파라미터에는 함수에서 쓰이는

상태 값들을 배열에 넣는다.

 

사실상 겉으로 보기에 useCallback을 쓰는것과 안쓰는것은 별반 차이가 없으나, 두번째 파라미터 배열에 담긴 상태 값들의 변경이 없을 경우에 렌더링이 되어도 메모이제이션으로 기억하고있던 함수를 반환하기 때문에 성능향상에 도움이 된다.

 

useMemo와의 차이점은 useMemo는 (컴포넌트 포함), useCallback은 함수를 호출한다는 점이다. 

 

모든 값들이 바뀔 때마다 전부 리렌더링을 해주면 상당히 비효율적일거 같은데, 다행히도 이런 함수들이 우리를 도와준다.

 

(이런 사소한것들을 놓치면 언제 어떤 상태 값 때문에 리렌더링이 되는지 모르게되고, 콘솔창에 여러 값들이 반복되어 마구 찍히는것을 볼 수 있다는점..)

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | Context API 전역 값 관리(1)  (0) 2021.09.17
React.js | 입문 | React.memo  (0) 2021.09.17
React.js | 입문 | 커스텀 Hook  (0) 2021.09.17
React.js | 입문 | useReducer  (0) 2021.09.17
React.js | 입문 | useMemo  (0) 2021.09.17
728x90
반응형

컴포넌트를 만들다 보면 반복되는 로직이 자주 발생하게되기 마련인데, 이를 모듈화해서 재사용할 수 있는 방법이 있다.

예를들어 Input을 관리하는 부분을 커스텀 Hook을 만들어서 쉽게 재사용할 수 있도록 구현해보겠다.

 

먼저 파일을 만들어준다.

 

useInput.js

import { useState, useCallback } from 'react';

function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);
  // change
  const onChange = useCallback(e => {
    const { name, value } = e.target;
    setForm(form => ({ ...form, [name]: value }));
  }, []);
  const reset = useCallback(() => setForm(initialForm), [initialForm]);
  return [form, onChange, reset];
}

export default useInputs;

 

그 다음 useReducer에서 사용하는 inputs를 없애고 useInput을 넣어준다.

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
import useInputs from './hooks/useInputs';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

const initialState = {
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]
};

function reducer(state, action) {
  switch (action.type) {
    case 'CREATE_USER':
      return {
        users: state.users.concat(action.user)
      };
    case 'TOGGLE_USER':
      return {
        users: state.users.map(user =>
          user.id === action.id ? { ...user, active: !user.active } : user
        )
      };
    case 'REMOVE_USER':
      return {
        users: state.users.filter(user => user.id !== action.id)
      };
    default:
      return state;
  }
}

function App() {
  const [{ username, email }, onChange, reset] = useInputs({
    username: '',
    email: ''
  });
  const [state, dispatch] = useReducer(reducer, initialState);
  const nextId = useRef(4);

  const { users } = state;

  const onCreate = useCallback(() => {
    dispatch({
      type: 'CREATE_USER',
      user: {
        id: nextId.current,
        username,
        email
      }
    });
    reset();
    nextId.current += 1;
  }, [username, email, reset]);

  const onToggle = useCallback(id => {
    dispatch({
      type: 'TOGGLE_USER',
      id
    });
  }, []);

  const onRemove = useCallback(id => {
    dispatch({
      type: 'REMOVE_USER',
      id
    });
  }, []);

  const count = useMemo(() => countActiveUsers(users), [users]);
  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : {count}</div>
    </>
  );
}

export default App;

 

 

기존코드는 아래와같이 일일이 하나씩 선언을 해준것에 비해

const { username, email } = state.inputs;
  
const onChange = useCallback(e => {
    const { name, value } = e.target;
    dispatch({
      type: 'CHANGE_INPUT',
      name,
      value
    });
  }, []);

 

 

커스텀 Hook을 사용해 더 간결하게 불러왔다.

  const [{ username, email }, onChange, reset] = useInputs({
    username: '',
    email: ''
  });

 

참조 

https://react.vlpt.us/basic/21-custom-hook.html

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | React.memo  (0) 2021.09.17
React.js | 입문 | useCallback  (0) 2021.09.17
React.js | 입문 | useReducer  (0) 2021.09.17
React.js | 입문 | useMemo  (0) 2021.09.17
React.js | 입문 | useEffect  (0) 2021.09.17
728x90
반응형

우리가 이전에 만든 사용자 리스트 기능에서의 주요 상태 업데이트 로직은 App 컴포넌트 내부에서 이루어졌었다.

상태를 관리 할 때 useState말고 useReducer라는 Hook 함수도 쓰인다. 이 함수를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리하는 것이 가능하다.

 

우선 reducer가 무엇인지부터 알아보자. reducer란 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환

해주는 함수이다.

function reducer(state, action) {
  // 새로운 상태를 만드는 로직
  // const nextState = ...
  return nextState;
}

return되는 값이 곧 새로운 상태가 된다.

 

여기서 action은 업데이트를 위한 정보를 가지고 있다. 주로 type 값을 지닌 객체로 사용한다.

// 카운터에 1을 더하는 액션
{
  type: 'INCREMENT'
}
// 카운터에 1을 빼는 액션
{
  type: 'DECREMENT'
}
// input 값을 바꾸는 액션
{
  type: 'CHANGE_INPUT',
  key: 'email',
  value: 'tester@react.com'
}
// 새 할 일을 등록하는 액션
{
  type: 'ADD_TODO',
  todo: {
    id: 1,
    text: 'useReducer 배우기',
    done: false,
  }
}

 

 

자 그럼 useReducer의 틀을 일단 만들어보자.

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

const initialState = {
  inputs: {
    username: '',
    email: ''
  },
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]
};

function reducer(state, action) {
  return state;
}

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { users } = state;
  const { username, email } = state.inputs;

  return (
    <>
      <CreateUser username={username} email={email} />
      <UserList users={users} />
      <div>활성사용자 수 : 0</div>
    </>
  );
}

export default App;

 

 

그 다음 onChange를 구현해보자

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

const initialState = {
  inputs: {
    username: '',
    email: ''
  },
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]
};

function reducer(state, action) {
  switch (action.type) {
    case 'CHANGE_INPUT':
      return {
        ...state,
        inputs: {
          ...state.inputs,
          [action.name]: action.value
        }
      };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { users } = state;
  const { username, email } = state.inputs;

  const onChange = useCallback(e => {
    const { name, value } = e.target;
    dispatch({
      type: 'CHANGE_INPUT',
      name,
      value
    });
  }, []);

  return (
    <>
      <CreateUser username={username} email={email} onChange={onChange} />
      <UserList users={users} />
      <div>활성사용자 수 : 0</div>
    </>
  );
}

export default App;

 

 

먼저 useReducer와 상태들을 선언해주고,

const [state, dispatch] = useReducer(reducer, initialState);
  const { users } = state;
  const { username, email } = state.inputs;

 

 

그 다음 reducer에 관한 함수를 정의해주고,

function reducer(state, action) {
  switch (action.type) {
    case 'CHANGE_INPUT':
      return {
        ...state,
        inputs: {
          ...state.inputs,
          [action.name]: action.value
        }
      };
    default:
      return state;
  }
}

 

 

onChange 함수에 dispatch 함수를 넣어준다.

  const onChange = useCallback(e => {
    const { name, value } = e.target;
    dispatch({
      type: 'CHANGE_INPUT',
      name,
      value
    });
  }, []);

 

dispatch함수로 action 에 type, name, value를 넣어서 reducer를 실행해주면 return으로 최신 상태가 반환하게된다.

 

 

이번엔 추가, 수정, 삭제를 구현해보았다.

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

const initialState = {
  inputs: {
    username: '',
    email: ''
  },
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]
};

function reducer(state, action) {
  switch (action.type) {
    case 'CHANGE_INPUT':
      return {
        ...state,
        inputs: {
          ...state.inputs,
          [action.name]: action.value
        }
      };
    case 'CREATE_USER':
      return {
        inputs: initialState.inputs,
        users: state.users.concat(action.user)
      };
    case 'TOGGLE_USER':
      return {
        ...state,
        users: state.users.map(user =>
          user.id === action.id ? { ...user, active: !user.active } : user
        )
      };
    case 'REMOVE_USER':
      return {
        ...state,
        users: state.users.filter(user => user.id !== action.id)
      };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  const nextId = useRef(4);

  const { users } = state;
  const { username, email } = state.inputs;

  const onChange = useCallback(e => {
    const { name, value } = e.target;
    dispatch({
      type: 'CHANGE_INPUT',
      name,
      value
    });
  }, []);

  const onCreate = useCallback(() => {
    dispatch({
      type: 'CREATE_USER',
      user: {
        id: nextId.current,
        username,
        email
      }
    });
    nextId.current += 1;
  }, [username, email]);

  const onToggle = useCallback(id => {
    dispatch({
      type: 'TOGGLE_USER',
      id
    });
  }, []);

  const onRemove = useCallback(id => {
    dispatch({
      type: 'REMOVE_USER',
      id
    });
  }, []);

  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : 0</div>
    </>
  );
}

export default App;

 

참조

https://react.vlpt.us/basic/20-useReducer.html

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | useCallback  (0) 2021.09.17
React.js | 입문 | 커스텀 Hook  (0) 2021.09.17
React.js | 입문 | useMemo  (0) 2021.09.17
React.js | 입문 | useEffect  (0) 2021.09.17
React.js | 입문 | 배열에 항목 수정 및 제거  (0) 2021.09.17
728x90
반응형

1. 컴포넌트가 리렌더링 될 때마다를 기록하고 싶을 때가 있을 수 있다.

 

App.js

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

function App() {
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  const { username, email } = inputs;
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };
  const [users, setUsers] = useState([
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]);

  const nextId = useRef(4);
  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  };

  const onRemove = id => {
    // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = user.id 가 id 인 것을 제거함
    setUsers(users.filter(user => user.id !== id));
  };
  const onToggle = id => {
    setUsers(
      users.map(user =>
        user.id === id ? { ...user, active: !user.active } : user
      )
    );
  };
  const count = countActiveUsers(users);
  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
      <div>활성사용자 수 : {count}</div>
    </>
  );
}

export default App;

 

위 컴포넌트를 보면

 

const count = countActiveUsers(users);

위 부분은 함수 리렌더링이 있을 때마다 count값을 바꿔서 나타내어지게끔 변수를 선언한 부분이며 

 

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

위 부분은 함수가 호출되었을 때 로그가 찍히도록 하고, user.active의 개수를 return해준다.

 

이렇게 코드를 구성하게 되면 버튼을 클릭할 때는 한 번 클릭할 때마다 제대로 로그가 찍히지만

input의 값이 바뀔 때마다 리렌더링이 되기 때문에 text 등을 입력할 때 상당히 비효율적이다.

 

이러한 상황에서 쓰이는 Hook 함수가 useMemo이다.

 

 

const count = useMemo(() => countActiveUsers(users), [users]);

이런식으로 첫번째 파라미터에는 어떻게 연산할지 함수를 정의하고, 두번째 파라미터는 바뀌는 내용을 정의한다.

이렇게 하면 users의 내용이 바뀌기 전까진 함수가 실행되지 않고, 바뀌면 그 때 실행이 된다.

 

 

 

참조

https://react.vlpt.us/basic/17-useMemo.html

728x90
반응형
728x90
반응형

useEffect는 useState로 선언한 상태를 관리하기에 정말 좋은 Hook이다.

컴포넌트가 마운트 됐을 때(처음 나타났을 때,), 언마운트 됐을 때(사라질 때), 업데이트 될 때(특정 props가 바뀔 때)

특정 작업을 처리할 수 있게 해준다.

 

1. 마운트 됐을 때 처리

useEffect(() => {
    console.log('컴포넌트가 화면에 나타남');
    return () => {
      console.log('컴포넌트가 화면에서 사라짐');
    };
  }, []);

이런식을 두번째 파라미터에 빈 배열( deps )을 넣어주면 처음 나타났을 때 특정 작업을 처리할 수 있게 해준다.

 

 

2. deps에 특정 값 추가( 업데이트 될 때 )

useEffect(() => {
    console.log('user 값이 설정됨');
    console.log(user);
    return () => {
      console.log('user 가 바뀌기 전..');
      console.log(user);
    };
  }, [user]);

두번째 파라미터 배열 안에 원하는 상태 변수를 넣어 해당 변수에 변경 사항이 있을 경우 특정 작업을 처리할 수 있게끔

해준다.

 

 

3. deps 파라미터 생략

useEffect(() => {
    console.log(user);
  });

deps 파라미터를 생략하면 컴포넌트가 리렌더링 될 때마다 특정 작업을 실행할 수 있게 해준다.

 

 

 

 

 

- 참조 

https://react.vlpt.us/basic/16-useEffect.html

728x90
반응형
728x90
반응형

전체 코드

 

App.js

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function App() {
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  const { username, email } = inputs;
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };
  const [users, setUsers] = useState([
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]);

  const nextId = useRef(4);
  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  };

  const onRemove = id => {
    // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = user.id 가 id 인 것을 제거함
    setUsers(users.filter(user => user.id !== id));
  };
  const onToggle = id => {
    setUsers(
      users.map(user =>
        user.id === id ? { ...user, active: !user.active } : user
      )
    );
  };
  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
    </>
  );
}

export default App;

 

UserList.js

import React from 'react';

function User({ user, onRemove, onToggle }) {
  return (
    <div>
      <b
        style={{
          cursor: 'pointer',
          color: user.active ? 'green' : 'black'
        }}
        onClick={() => onToggle(user.id)}
      >
        {user.username}
      </b>
      &nbsp;
      <span>({user.email})</span>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}

function UserList({ users, onRemove, onToggle }) {
  return (
    <div>
      {users.map(user => (
        <User
          user={user}
          key={user.id}
          onRemove={onRemove}
          onToggle={onToggle}
        />
      ))}
    </div>
  );
}

export default UserList;

 

 

1. 수정 - UserList에서 onToggle 함수를 User 컴포넌트에 props로 전달하고, 인자로 users.id를 담아 실행해주도록  한다.

   users 배열이 반복문으로 각기 다른 id를 onToggle함수에 보내줄 것이고, 인자로 전해준 id가 원래있던 user와 같을 

   경우에 조건문을 처리해준다. 다를 경우에는 원래 그 상태를 유지한다.

  const onToggle = id => {
    setUsers(
      users.map(user =>
        user.id === id ? { ...user, active: !user.active } : user
      )
    );
  };

 

 

2. 삭제 

  const onRemove = id => {
    // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = user.id 가 id 인 것을 제거함
    setUsers(users.filter(user => user.id !== id));
  };

 

 

참조

https://react.vlpt.us/basic/15-array-modify.html

 

 

 

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | useMemo  (0) 2021.09.17
React.js | 입문 | useEffect  (0) 2021.09.17
React.js | 입문 | 배열에 항목 추가  (0) 2021.09.17
React.js | 입문 | 배열 렌더링  (0) 2021.09.17
React.js | 입문 | useRef  (0) 2021.09.16
728x90
반응형

 전체 코드

 

App.js

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function App() {
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  const { username, email } = inputs;
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };
  const [users, setUsers] = useState([
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com'
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com'
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com'
    }
  ]);

  const nextId = useRef(4);
  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers([...users, user]);

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  };
  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} />
    </>
  );
}

export default App;

 

첫번째 방법으로는 Spread 연산자를 사용해서 

 

setUsers([...users, user]);

이런식으로 추가를 해주는 방법이 있고, 

 

두번째 방법으로는

 

setUsers(users.concat(user));

이런식으로 concat 함수를 사용하는 방법이 있다.

 

 

참조

https://react.vlpt.us/basic/13-array-insert.html

728x90
반응형
728x90
반응형

리액트에서는 컴포넌트를 선언할 때, 속성을 전달할 수 있다.

JQuery에서는 페이지 내에서 객체를 선언하고, 다른 페이지로 그 객체를 전달하려면 백엔드를 거쳐야 했지만, 

리액트같은 경우에 보다 편리한 방법으로 객체를 전달할 수 있다.

 

App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello name="react" />
  );
}

export default App;

 

Hello 파일의 컴포넌트를 가져와서 선언하고, return될 때 사용되게끔 했다. 또한 name = "react" 라는 값을 보내주었다.

 

Hello.js

import React from 'react';

function Hello(props) {
  return <div>안녕하세요 {props.name}</div>
}

export default Hello;

 

그럼 이처럼 함수의 인자값으로 props 안에 name이 들어가게되고, 아까 보내주었던 name을 컴포넌트에서

사용할 수 있다.

 

만약 컴포넌트에 props를 지정하지 않았을 경우에 default 값도 설정해줄 수 있는데,

 

import React from 'react';

function Hello({ color, name }) {
  return <div style={{ color }}>안녕하세요 {name}</div>
}

Hello.defaultProps = {
  name: '이름없음'
}

export default Hello;

이런식으로 사용이 가능하다.

 

컴포넌트끼리 원하는 객체나 변수를 주고 받는 기능은 매우 유용하다고 느꼈다.

 

-참조

https://react.vlpt.us/basic/05-props.html

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | useState  (0) 2021.09.16
React.js | 입문 | 조건부 렌더링  (0) 2021.09.16
React.js | 입문 | JSX  (0) 2021.09.16
React.js | 입문 | 컴포넌트 만들기  (0) 2021.09.16
React.js | 입문 | React hook  (0) 2021.09.15

+ Recent posts