본문 바로가기

React

20210610 React09 : 컴포넌트간 통신(상하, 하상), Context API & useContext(데이터 set, 데이터 get 3가지 방식/Cunsumer, Class static, Function useContext)

React 09



컴포넌트 간 통신


하위 컴포넌트 변경 하기


  • 예시
    • 상위 컴포넌트에서 하위 컴포넌트에서 쓰이는 state의 값을 변경 하는 경우
    • A컴포넌트(버튼) -> B컴포넌트 -> C컴포넌트 -> D컴포넌트 -> E컴포넌트(pros.value)
    • A에 있는 버튼을 클릭해서 E컴포넌트에 있는 value를 변경하는 것
    • 상위 컴포넌트의 state 값을 props로 내려서 변경함
import { useState } from "react";

export default function A() {
  const [value, setValue] = useState("아직 안바뀜");
  return (
    <div>
      <B value={value} />
      <button onClick={click}>E의 값을 바꾸기</button>
    </div>
  );
  function click() {
    setValue("E의 값을 변경");
  }
}

function B({ value }) {
  return (
    <div>
      <p>여긴 B</p>
      <C value={value} />
    </div>
  );
}

function C({ value }) {
  return (
    <div>
      <p>여긴 C</p>
      <D value={value} />
    </div>
  );
}

function D({ value }) {
  return (
    <div>
      <p>여긴 D</p>
      <E value={value} />
    </div>
  );
}

function E({ value }) {
  return (
    <div>
      <p>여긴 E</p>
      <h3>E에 있는 값 : {value}</h3>
    </div>
  );
}



상위 컴포넌트를 변경하기


  • 예시
    • 하위 컴포넌트에서 상위 컴포넌트의 값을 변경하는 경우
    • E컴포넌트(버튼) -> D컴포넌트 -> C컴포넌트 -> B컴포넌트 -> A컴포넌트(pros.value)
    • 상위 컴포넌트의 state 변경하는 함수 자체를 props로 전달하여 하위 컴포넌트로 내려서 하위 컴포넌트에서 state 값을 변경함
export default function A() {
  const [value, setValue] = useState("아직 안바뀜");
  //setValue를 그대로 전달해도 되고, setValue를 실행하는 함수를 만들어서 전달해도 됨
  return (
    <div>
      <p>A에 있는 값 : {value}</p>
      <B setValue={setValue} />
    </div>
  );
}
function B({ setValue }) {
  return (
    <div>
      <p>여긴 B</p>
      <C setValue={setValue} />
    </div>
  );
}
function C({ setValue }) {
  return (
    <div>
      <p>여긴 C</p>
      <D setValue={setValue} />
    </div>
  );
}
function D({ setValue }) {
  return (
    <div>
      <p>여긴 D</p>
      <E setValue={setValue} />
    </div>
  );
}
function E({ setValue }) {
  const click = () => {
    setValue("A의 값을 변경!");
  };
  return (
    <div>
      <p>여긴 E</p>
      <button onClick={click}>A의 값 바꾸기</button>
    </div>
  );
}


결론


  • 둘다, 일단 state를 공유하기 위해서는 상위 컴포넌트에서 state를 정의하여야 한다.
    • state 값을 변경하는것을 공유하거나, state 값을 표현하기 위해 공유하는 작업에서
    • 상위 컴포넌트에서 정의된 state를 하위 컴포넌트가 값을 변경하는 경우setState 함수를 내리고
    • 상위 컴포넌트에서 정의된 state를 하위 컴포넌트에서 값을 표현하는 경우state 자체를 내림
  • component가 복잡해 질수록 이러한 state를 props을 통해 내려 보내는 작업에 주의를 기울여야함



Context API & useContext


  • context 또한 react에 내장되어 있는 API 임
  • react : context API
  • 컴포넌트 간에 데이터를 공유하는 경우 props를 계속 전달해줘야 하는 과정이 번거러움,
  • 그래서 context API를 통해 props로 넘겨주지 않아도 많은 컴포넌트가 여러한 값을 공유하도록 할 수 있음

하위 컴포넌트 전체에 데이터를 공유하는 법

  • 데이터를 set하는 놈
    • 가장 상위 컴포넌트 -> provider (프로바이더)로 가장 상위 컴포넌트를 감싸서 사용

  • 데이터를 get하는 놈
    • 모든 하위 컴포넌트에서 접근 가능
      • consumer(컨슈머)로 하는 방법
      • class 컴포넌트의 this.context로 하는 방법
      • funcitonal 컴포넌트의 useContext로 하는 방법

데이터를 set 하기

  • 컨텍스트 생성하기 -> 컨텍스트.프로바이더 사용 -> value를 사용
// PersonContext.js
import React from "react";

const PersonContext = React.createContext();

export default PersonContext;
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import PersonContext from "./contexts/PersonContext";

const persons = [
  { id: 0, name: "kim", age: 24 },
  { id: 1, name: "park", age: 35 },
];

ReactDOM.render(
  <React.StrictMode>
    <PersonContext.Provider value={persons}>
      {/*provider 하위에 있는 컴포넌트가 모두 공유하는 데이터를 설정할 수 있음 */}
      <App />
    </PersonContext.Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

데이터를 get 하기 01 : Consumer 방식

  • class, function 모두 범용적으로 사용할 수 있는 방식
  • context를 가져온다 -> context.consumer를 사용한다. -> value를 사용함
//Ex01.jsx
// context가져오기
import PersonContext from "../contexts/PersonContext";

export default function Example1() {
  return (
    // Consumer 사용해서 안에 함수를 넣어 공유하기로 한 값을 활용해서 Example1 컴포넌트가 render할 부분을 꾸민다.
    <PersonContext.Consumer>
      {(persons) => (
        <ul>
          {persons.map((person) => (
            <li>{person.name}</li>
          ))}
        </ul>
      )}
    </PersonContext.Consumer>
  );
}
import logo from "./logo.svg";
import "./App.css";
import Example1 from "./components/Ex01";
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Example1 />
      </header>
    </div>
  );
}

export default App;



데이터를 get 하기 02 : class component 방식 (비추천)

  • static contextType에 context를 설정 -> this.context = value 임
  • 단점: static contextType의 경우 여러가지를 지정할 수 없음
    • persons 말고 다른 데이터를 동시에 가져와서 사용하는 경우 사용이 불가함
import React from "react";
// context 가져오기
import PersonContext from "../contexts/PersonContext";

export default class Example2 extends React.Component {
  // contextType 을 static으로 넣어 Context를 연결
  static contextType = PersonContext;

  render() {
    // this.context가 해당 값을 의미
    // [
    //   { id: 0, name: "kim", age: 24 },
    //   { id: 1, name: "park", age: 35 },
    // ];
    // persons 변수로 받아와 사용
    const persons = this.context;

    return (
      <ul>
        {persons.map((person) => (
          <li>{person.name}</li>
        ))}
      </ul>
    );
  }
}
// static contextType 코드 부분을 대체할 수 있음
// Example2.contextType = PersonContext;



데이터를 get 하기 03 : function component 방식 (추천)

  • useContext 훅 으로 context를 인자로 호출 -> useContext의 return이 value 임
  • 여러가지 context를 가져다 사용할 수 도 있음
import { useContext } from "react";
// Context 가져오기
import PersonContext from "../contexts/PersonContext";

export default function Example3() {
  // Context uesContext에 넣어 연결하고, 해당 값 가져오기
  const persons = useContext(PersonContext);
  return (
    // 값 사용하기
    <ul>
      {persons.map((person) => (
        <li>{person.name}</li>
      ))}
    </ul>
  );
}