#!/usr/bin/env python
# coding: utf-8
# # ReactのContext周りについて
#
# - 2018/11/14 勉強会
# # アジェンダ
#
# 1. ContextAPI概要
# 1. APIの紹介
# 1. Reduxとの使い分け
# 1. Hooksを使う
# 1. 先日のreact-reduxのリリースについて
# 1. 参考
# # ContextAPI概要
#
#
# ## 従来のReact
#
# - 親から子へデータを渡すときはpropsを使う
#
# ```
# // 親
# export default class Parent extends React.Component {
# render() {
# const count = 1;
# // `count`を子孫にわたす
# return ;
# }
# }
#
# // 子
# const Child = ({ count }) =>
count: {count}
;
# ```
# ### もっと入れ子&複数propsになるとき
#
# - 親→子→孫→..と、渡すときにバケツリレーが続いてしまう
# - これを`Prop Drilling`問題という
#
# ```
# // 親 データを子に渡す
# export default class Parent extends React.Component {
# render() {
# const count = 1;
# const word = 'hello';
#
# return ;
# }
# }
#
# // 子 ここでは使わない
# const Child = ({ count, word }) => ;
#
# // 孫 ここでも使わない
# const Grandson = ({ count, word }) => ;
#
# // 曾孫 やっとここで使いたい
# const GreatGrandchild = ({ count, word }) => (
# <>
# count: {count}
# word: {word}
# >
# );
# ```
# ## 従来の解決の仕方
#
# - Reduxを使う
# - spread attributesを使って全渡しする
# - {...props}みたいなやつ
# - 本質的な解決法ではない
# ## [ContextAPI](https://reactjs.org/docs/context.html)とは
#
# - React製
# - contextを使って子孫にデータを送る
#
# ## ContextAPIを用いた最小の例
#
# ```
# import React, { createContext } from 'react';
#
# const { Provider, Consumer } = createContext();
#
# const SimpleContextAPIParent = () => (
#
#
#
# );
# export default SimpleContextAPIParent;
#
# // 子 propsを伝搬させてない
# const Child = () => ;
#
# // 孫 同じく伝搬させてない
# const Grandson = () => ;
#
# const GreatGrandchild = () => (
#
# {({ count, word }) => (
# <>
# values: {count}
# word: {word}
# >
# )}
#
# );
#
# ```
#
#
# ### APIの解説
#
# #### [React.createContext](https://reactjs.org/docs/context.html#reactcreatecontext)
#
# - 後述するProviderとConsumerをペアで返す
# - 上記の例のように2値を一気に受け取る方法もあるが、
# - 以下のようにContextに名前をつける方法もある
# - 使いたいContextが複数あるなら便利
# ```
# const Root = React.createContext;
# ...
#
# ...
#
# ```
# - 引数にはdefault値を入れる
# - 使い所がよくわからんので調べる
#
# #### [Provider](https://reactjs.org/docs/context.html#contextprovider)
#
# - Consumerにcontextを渡すコンポーネント
# - `value`を使って渡す
# - 値だけでなく関数も渡せる
# - (ReduxのProviderと同じような機能で、全く同じ名前なのは..🤬🤬)
#
# #### [Consumer](https://reactjs.org/docs/context.html#contextconsumer)
#
# - Providerからcontextを受け取る
# - 中には関数を書く
# ```
#
# {() => なんか}
#
# ```
#
# ### ちなみに
#
# - 公式の例では
# - 「テーマカラー」や「ログイン中ユーザー」など、「状態が頻繁に変わるわけではないが、いろんなコンポーネントからアクセスされるデータ」をContextに渡している
# ## 少し拡張したコードを書いてみる
#
# - 次の例では
# - まだ紹介していない`Class.contextType`も使う
# - 関数も渡す
#
#
# ```
# import React from 'react';
#
# // 名前を付けてcontextを作る
# const CounterContext = React.createContext();
#
# // 親
# export default class ExtendedParent extends React.Component {
# constructor(props) {
# super(props);
# this.state = {
# count: 0 // stateを定義
# };
# }
#
# increment = () => {
# this.setState({
# count: this.state.count + 1
# });
# };
#
# render() {
# return (
#
#
#
# );
# }
# }
#
# // 子 何もしてない
# const Child = () => ;
#
# // 孫 これはclass
# class Grandson extends React.Component {
# static contextType = CounterContext; // contextTypeを使う
#
# componentDidMount() {
# // lifecycleの中でもcontextにアクセスできる
# console.log(this.context.count);
# }
#
# render() {
# const { count, increment } = { ...this.context }; // contextを受け取る
# return (
# <>
# count: {count}
#
# >
# );
# }
# }
# ```
# ### 解説
#
# #### [Class.contextType](https://reactjs.org/docs/context.html#classcontexttype)
#
# - 前の例と同じように、Childコンポーネントではなにもしていない
# - `value`で値と一緒に関数も渡している
# ```
#
# ...
# ```
# - 孫コンポーネントの以下の部分でcontextを受け取っている
# - `static contextTypes = CounterContext`
# - 受け取ったcontextは`this.context.hogehoge`で利用できる
#
# - createContext()の引数=初期値がよくわからん
#
#
# Consuming Multiple Contexts
#
# https://reactjs.org/docs/context.html#consuming-multiple-contexts
# 複雑性が増しそう
# ## Reduxとの使い分け
#
# - 今後もReduxを使っていくが
# - 小規模だったり、ギリReduxを使いたくないぐらいのときに使えそう
# - それ以上の規模のときに使うとぐちゃりそう
#
# - ReduxはReactの旧Context機能を使って実装されている
# ## Hooksを使う
#
# - だいぶ簡素にかける
#
#
# ```
# import React, { createContext, useState, useContext } from 'react';
#
# // contextを作る
# const CounterContext = createContext();
#
# // 親
# const HooksParent = () => {
# const [num, setNum] = useState(0);
# return (
# setNum(num + 1)
# }}
# >
#
#
# );
# };
# export default HooksParent;
#
# // 子
# const Child = () => ;
#
# // 孫
# const Grandson = () => {
# const counter = useContext(CounterContext); // hooksを使う
# return (
# // いつも通りの書き方できる
# <>
# {counter.num}
#
# >
# );
# };
# ```
#
#
#
# ### 解説
#
# - Consumerを使わずにcontextを受け取れる
# - 今まではConsumerの中に関数を書いたりしないといけなかったが、それもなくなり通常通りの書き方できる
#
# ## ContextAPI + react-redux
#
# - 先日のリリース
# - [Release v6.0.0-beta.1 · reduxjs/react-redux](https://github.com/reduxjs/react-redux/releases/tag/v6.0.0-beta.1)
# - `yarn add react-redux@next`で入れる
# - `yarn add redux` reduxも
# - [テストコード](https://github.com/reduxjs/react-redux/blob/85fb553ba8e3f4b0efc158d2e48aafb4c18a04d4/test/components/Provider.spec.js)を参考に
# - `ReactReduxContext`というコンポーネントが用意された
#
#
#
#
# ## reduxっぽいやつ(未完成)
#
# - hooksも使いたい
# - https://github.com/HriBB/react-repro/blob/e3177115ae655c7392fda182d4cdd39a70e6628a/pages/index.js
#
# ```
# import React from 'react';
#
# // store的ななにか
# const store = new class {
# state = {
# num: 0
# };
# actions = fn => {
# console.log(this.state);
# this.state = fn(this.state);
# };
# // actions: fn => {
# // this.state = fn(this.state);
# // }
# // actions: {
# // increment: () => {
# // this.state.num += 1;
# // }
# // }
# }();
#
# // contextを作る
# const CounterContext = React.createContext({ num: 0 });
#
# // 親
# export default class Parent extends React.Component {
# render() {
# return (
#
# parenat: {store.state.num}
# num
#
#
# );
# }
# }
#
# // 子
# const Child = () => ;
#
# // 孫
# // // これはclass
# class Grandson extends React.Component {
# static contextType = CounterContext;
# render() {
# const { state, actions } = { ...this.context };
# console.log(state);
# console.log(actions);
# return (
# <>
# {state.num}
#
# >
# );
# }
# }
#
# // Consumer使う版
# // const Grandson = () => (
# //
# // {({ state, actions }) => (
# //
# //
{state.num}
# //
# //
# // )}
# //
# // );
# ```
#