// 親
export default class Parent extends React.Component {
render() {
const count = 1;
// `count`を子孫にわたす
return <Child count={count} />;
}
}
// 子
const Child = ({ count }) => <div>count: {count}</div>;
Prop Drilling
問題という// 親 データを子に渡す
export default class Parent extends React.Component {
render() {
const count = 1;
const word = 'hello';
return <Child count={count} word={word} />;
}
}
// 子 ここでは使わない
const Child = ({ count, word }) => <Grandson count={count} word={word} />;
// 孫 ここでも使わない
const Grandson = ({ count, word }) => <GreatGrandchild count={count} word={word} />;
// 曾孫 やっとここで使いたい
const GreatGrandchild = ({ count, word }) => (
<>
<div>count: {count}</div>
<div>word: {word}</div>
</>
);
import React, { createContext } from 'react';
const { Provider, Consumer } = createContext();
const SimpleContextAPIParent = () => (
<Provider value={{ count: 1, word: 'hello' }}>
<Child />
</Provider>
);
export default SimpleContextAPIParent;
// 子 propsを伝搬させてない
const Child = () => <Grandson />;
// 孫 同じく伝搬させてない
const Grandson = () => <GreatGrandchild />;
const GreatGrandchild = () => (
<Consumer>
{({ count, word }) => (
<>
<div>values: {count}</div>
<div>word: {word}</div>
</>
)}
</Consumer>
);
const Root = React.createContext;
...
<Root.Provider />
...
<Root.Consumer />
value
を使って渡す<Consumer>
{() => なんか}
</Consumer>
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 (
<CounterContext.Provider
value={{ count: this.state.count, increment: this.increment }} // 関数も渡す
>
<Child />
</CounterContext.Provider>
);
}
}
// 子 何もしてない
const Child = () => <Grandson />;
// 孫 これは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 (
<>
<p>count: {count}</p>
<button onClick={increment}>increment</button>
</>
);
}
}
value
で値と一緒に関数も渡している<CounterContext.Provider
value={{ num: this.state.num, increment: this.increment }}
>
...
static contextTypes = CounterContext
this.context.hogehoge
で利用できるConsuming Multiple Contexts
https://reactjs.org/docs/context.html#consuming-multiple-contexts 複雑性が増しそう
今後もReduxを使っていくが
小規模だったり、ギリReduxを使いたくないぐらいのときに使えそう
それ以上の規模のときに使うとぐちゃりそう
ReduxはReactの旧Context機能を使って実装されている
import React, { createContext, useState, useContext } from 'react';
// contextを作る
const CounterContext = createContext();
// 親
const HooksParent = () => {
const [num, setNum] = useState(0);
return (
<CounterContext.Provider
value={{
num,
increment: () => setNum(num + 1)
}}
>
<Child />
</CounterContext.Provider>
);
};
export default HooksParent;
// 子
const Child = () => <Grandson />;
// 孫
const Grandson = () => {
const counter = useContext(CounterContext); // hooksを使う
return (
// いつも通りの書き方できる
<>
<p>{counter.num}</p>
<button onClick={counter.increment}>increment</button>
</>
);
};
yarn add react-redux@next
で入れるyarn add redux
reduxもReactReduxContext
というコンポーネントが用意された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 (
<CounterContext.Provider value={store}>
<p>parenat: {store.state.num}</p>
<p>num</p>
<Child />
</CounterContext.Provider>
);
}
}
// 子
const Child = () => <Grandson />;
// 孫
// // これはclass
class Grandson extends React.Component {
static contextType = CounterContext;
render() {
const { state, actions } = { ...this.context };
console.log(state);
console.log(actions);
return (
<>
<p>{state.num}</p>
<button
onClick={() =>
actions(s => {
// console.log(s);
return {
...s,
num: s.num + 1
};
})
}
>
increment
</button>
</>
);
}
}
// Consumer使う版
// const Grandson = () => (
// <CounterContext.Consumer>
// {({ state, actions }) => (
// <div>
// <p>{state.num}</p>
// <button
// onClick={() =>
// actions(s => {
// console.log(s);
// return {
// ...s,
// num: s.num += 1
// };
// })
// }
// >
// increment
// </button>
// </div>
// )}
// </CounterContext.Consumer>
// );