Front-End/MobX

@inject 와 Provider

Voyage_dev 2022. 12. 16. 15:36

@inject 와 Provider

  • 프로바이더에 props로 넣고, @inject로 꺼내 쓴다고 보면 된다
    • 상당히 명시적이고 편하다
    • 컨테이너를 쓰지 않아도 될 것 같지만 컨테이너를 중간에 작성 해 주는것이 프레젠테이션 컴포넌트의 테스트와 분리를 위해서 훨씬 좋다
      • props로 바꿔준다
      • this.props.store

설정해 보자

// index.js
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider personStore={personStore}>
      <App />
    </Provider>
  </React.StrictMode>
);
// app.js
export default inject("personStore")(observer(App));

  • mobx-react에서 가져온 inject로 다시 한 번 감싸준다
  • 감싸면서 한 번 더 실행을 한다
  • 그 안에는 provider의 props로 지정해 줬던 이름을 그대로 문자열로 꺼내오게 된다
  • 이렇게 설정하면 App 안으로 personStore가 들어가게 된다
function App({personStore}) { // props로 넣어준다
//  const personStore = useContext(PersonContext);  이부분을 지운다

  const age10 = computed(() => {
    return Math.floor(personStore.age / 10) * 10;
  }).get();
  console.log(personStore.age, personStore.name);

  const click = () => {
    // personStore.plus();
    setTimeout(() => {
      personStore.testAction();
    }, 500);
  };
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          <button onClick={click}>plus</button>
        </p>
        <p>
          {personStore.age},{personStore.name}
        </p>
      </header>
    </div>
  );
}

이렇게 하고 실행을 해 보면

정상적으로 작동하는 걸 볼 수 있다.

 

이렇게 할 수 있는 것은 스토어가 하나가 아닌 mobx의 특징 때문이다. Redux의 provider 같은 경우 스토어 하나만 지정할 수 있도록 되어 있던 반면에 mobx는 여러개의 스토어를 가질 수 있도록 inject와 provider가 이런식으로 설정이 되어 있다.

 

이제 class형으로 설정해 보자

@inject("personStore")
@observer
class App extends React.Component {
  // static contextType = PersonContext;

  @autobind
  click() {
    // const personStore = this.context;
    this.props.personStore.plus();
  }

  render() {
    const { personStore } = this.props;
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            <button onClick={this.click}>plus</button>
          </p>
          <p>{personStore.age10}</p>
        </header>
      </div>
    );
  }
}

// export default inject("personStore")(observer(App));
export default App;

마지막으로 App 컴포넌트가 아니라 App 컨테이너를 만들고 그 안에서 App 컴포넌트로 전달해 보자

@inject("personStore")
@observer
class AppContainer extends React.Component {
  // static contextType = PersonContext;

  @autobind
  plus() {
    // const personStore = this.context;
    this.props.personStore.plus();
  }

  render() {
    const { personStore } = this.props;
    return <App age10={personStore.age10} plus={this.plus} />;
  }
}

function App({ age10, plus }) {
  const click = () => {
    plus();
  };
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          <button onClick={click}>plus</button>
        </p>
        <p>{age10}</p>
      </header>
    </div>
  );
}

// export default inject("personStore")(observer(App));
export default AppContainer;