Reactコンポーネントを外から操作したい

最近、Reactを触っているのだけど、Reactコンポーネント外から任意のReactコンポーネントを操作したい事情に駆られた(何を言ってるのか分からねぇと思うが俺も(ry)。

export default class Hoge extends Component {
  constructor(props) {
    super(props);
    this.state = { text: '' };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(e) {
      this.setState({ text: 'unko' });
  }
  render() {
      ...
  }
}

普通のケースだと、こんな感じでHogeのコンポーネントのどっかをクリックしたら、statetextunkoをセットすることによって、renderがはしるみたいな、わかりやすい。なんの問題ない。

ただ、このコンポーネントを、window.Hoge.setState({ text: 'unko' })みたいに、グローバルから操作したい場合ってどうしたらいいんだろうかとけっこう悩んだ。

re-render

export default class Hoge extends Component {
  render() {
      return(<span id='hoge'>{ this.props.text }</span>)
  }
}
window.Hoge = Hoge;

とりあえず、Hogeをグローバルのwindowに生やす。

export default class Fuga extends Component {
  constructor(props) {
    super(props);
    window.createHoge = (value) => {
      const Hoge = window.Hoge;
      const elm = document.getElementById('hoge');
      elm.innerHTML = '';
      ReactDOM.render(<Hoge text={value} />, elm);
    };
  }
}

親のコンポーネントなり、なんなりで、新規にHogeを作るグローバル関数を定義する。

window.createHoge('unko');

で、Hogeコンポーネントのpropsunko渡して、上書きすることでできた。なんか無理矢理感あるけど…

既にレンダリングしてあるHogeコンポーネントってどうやって取得したらいいんだろうか?( 謎

custom event

とりあえずunkoを表示できてホッとしてたけど、今度はこのunkoを他のコンポーネントに伝えたいって場合どうすればいいんだろうと悩んだ。

export default class Fuga extends Component {
  constructor(props) {
    super(props);
    window.createHoge = (value) => {
     const event = new CustomEvent('createHoge', { 'detail': value });
      document.getElementById('piyo').dispatchEvent(event);
      ...
    };
  }
}

createHogeのときに、createHogeイベントを発火させる。んで伝えたい値もセットしておく。

export default class Piyo extends Component {
  constructor(props) {
    super(props);
    this.state = { text: '' };
        this.handleHoge= this.handleHoge.bind(this);
  }
  componentDidMount() {
    this.refs.piyo.addEventListener('createHoge', this.handleHoge);
  }
  componentWillUnmount() {
    this.refs.piyo.removeListener('createHoge', this.handleHoge);
  }
  handleHoge(e) {
    this.setState({ text: e.detail });
  }
  render() {
      return(<span ref='piyo' id='piyo'>{this.state.text}</span>);
  }
}

受け手のコンポーネントPiyoでリッスン♪これで、window.createHoge('unko');することで、Hogeコンポーネントが作られ上書きし、Piyoコンポーネントにもunkoが表示される。

なんかMobXみたいなストア管理のライブラリ使えば、もっとシュッとできるんだろうなと思いつつ、しかし、そこまでの規模じゃないと思い、この結果に至りました。ちーん( ˘ω˘)