상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 속성값이 사용된다.

가까운 거리는 속성값으로 충분하지만, 그게 아니라면 속성값을 반복적으로 사용해야 한다.

이럴때, contextAPI로 비교적 쉽게 데이터를 전달할 수 있다!👍🏻

1. Context API

App Component -> Greeting Component

먼저, contextAPI를 사용하지 않을 때의 코드이다.
전달하고...전달하고...
Profile컴포넌트는 username을 사용하지 않고 전달만한다.

class App extends React.Component {
  render() {
    return (
      <div>
        <div>위쪽</div>
        <Profile username="sohee" />
        <div>아래쪽</div>
      </div>
    );
  }
}

function Profile({ username }) {
  return (
    <div>
      <Greeting username={username} />
      {/* ... */}
    </div>
  );
}

function Greeting({ username }) {
  return <p>{`${username}님 안녕하세요`}</p>
}

이번엔 ContextAPI를 사용한 예제이다.
createContext의 함수 구조는 아래와 같다.
React.createContext(defaultValue) => {Provider, Consumer}

const UserContext = React.createContext('unknown');

class App extends React.Component {
  render() {
    return (
      <div>
        <UserContext.Provider value="sohee">
          <div>위쪽</div>
          <Profile />
          <div>아래쪽</div>
        </UserContext.Provider>
      </div>
    );
  }
}

function Profile() {
  return (
    <div> 
      <Greeting />
      {/* ... */}
    </div>
  );
}

function Greeting() {
  return (
    <UserContext.Consumer>
      {username => <p>{`${username}님 안녕하세요`}</p>}
    </Usercontext.Consumer>
  );
}

상위 컴포넌트에서는 Provider를 이용하여 데이터를 전달한다.
하위 컴포넌트에서는 Consumer를 이용하여 데이터를 사용한다.
만약 상위로 올라가면서 Provider를 찾지 못한다면 default값을 사용한다.

2. 하위 컴포넌트에서 context data 수정

redux에서처럼 context data도 원하는 곳에서 변경할 수 있다.
count를 증가시키는 함수를 콘텍스트 데이터에 포함시킨다.
App의 onHello가 콘텍스트 데이터에 포함되므로 App의 onHello를 호출할 수 있다.

const Usercontext = React.createContext({
  username: 'unknown',
  count: 0,
  onHello: () => {},
});
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      username: 'sohee',
      count: 0,
      onHello: this.onHello,
    };
  }
  onHello = () => {
    const { count } = this.state;
    this.setState({ count: count + 1 });
  };
  render() {
    return (
      <div>
        <UserContext.Provider value={this.state}>
          <div>위쪽</div>
          <Profile />
          <div>아래쪽</div>
        </UserContext.Provider>
      </div>
    );
  }
}

function Greeting() {
  return (
    <UserContext.Consumer>
      {value => (
         <React.Fragment>
           <p>`${value.username}`</p>
           <p>{`인사 횟수: ${value.count}`</p>
           <button onClick={value.onHello}>인사하기</button>
         </React.Fragment>
      )}
    </Usercontext.Consumer>
  }
}

3. ref

React에서 DOM 요소에 직접 접근해야 할 때 ref를 사용한다.

아래 예제를 보면서 이해하자

class TextInput extends React.Component {
  textRef = React.createRef();
  componentDidMount() {
    this.setTextFocus();
  }
  setTextFocus() {
    this.textRef.current.focus();
  }
  render() {
    return (
      <div>
        <input type="text" ref={this.textRef} />
        <button>저장<button>
      </div>
    );
  }
}

createRef가 반환하는 ref객체를 이용해 자식요소에 접근한다.
refcurrent속성을 이용하여 inputfocus를 주었다.

함수형 컴포넌트에서 ref 사용하기

ref속성값은 클래스형 컴포넌트에서만 사용가능하다.
함수형에서는 내부 리액트 요소에 ref속성값을 주는 식으로 사용한다.
하지만 이 방법은 내부 구조를 외부에서 알아야 하므로 좋은 방법은 아니다.

function TextInput({ textRef }) {
  return (
    <div>
    <input type="text" ref={textRef} />
    </div>
  );
}
class Form extends React.Component {
  textRef = React.createRef();
  componentDiMount() {
    this.setTextFocus();
  }
  setTextFocus = () => {
    this.textRef.current.focus();
  };
  render() {
    return (
      <div>
        <TextInput textRef={this.textRef} />
        <button onClick={this.setTextFocus}>텍스트로 이동</button>
      </div>
    );
  }
}
`