React復号:React Hooks関数のuseContext


useContext関数はReact Hooksの3つの基礎hooks関数の1つです.あまり話さないで、まず使い方を見てみましょう.
const value = useContext(MyContext);

contextオブジェクト(React.createContextの戻り値)を受信し、contextの現在の値を返します.現在のcontext値は、上位コンポーネントのうち、現在のコンポーネントに最も近いvalue propによって決定される.コンポーネント上位レイヤの最近のが更新されると、Hookは再レンダリングをトリガーし、MyContext providerに最新に渡されたcontext valueの値を使用します.祖先がReact.memoまたはshouldComponentUpdateを使用していた場合でも、コンポーネント自体がuseContextを使用しているときに再レンダリングされます.useContextが呼び出されたコンポーネントは、context値が変化したときに再レンダリングされます.再レンダリングコンポーネントのオーバーヘッドが大きい場合は、memoizationを使用して最適化できます.
注意:useContext(MyContext)は、contextの値とcontextの変化を読み取ることができるだけです.を使用して、下位コンポーネントにcontextを提供する必要があります.
Contextはいつ使用しますか?
Context設計の目的は、現在認証されているユーザー、トピック、または優先言語など、コンポーネントツリーにとって「グローバル」であるデータを共有することです.たとえば、次のコードでは、ボタンコンポーネントのスタイルを「theme」プロパティで手動で調整します.
// Context                  ,            。
//      theme      context(“light”    )。
const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
    //      Provider       theme          。   
    //     ,           。    
    //       ,    “dark”           。    
    return (
                  
                
          
        );
      }
}

//                 theme  。
function Toolbar() {  return (
    
); } class ThemedButton extends React.Component { // contextType theme context。 // React theme Provider, 。 // , theme “dark”。 static contextType = ThemeContext; render() { return

使用 context, 我们可以避免通过中间元素传递 props.

Context是最好的解决方案吗?

Context                            。     ,              。

いくつかのプロパティを階層的に渡すのを避けたい場合は、コンポーネントの組み合わせ(component composition)はcontextよりも良いソリューションである場合があります.
私たちはこのようなシーンを考えています.
PageコンポーネントにはLinkコンポーネントがあり、LinkコンポーネントにはUserコンポーネントがあります.では、データはPageコンポーネントからUserコンポーネントに渡さなければなりません.中間のLinkコンポーネントは、データを処理しません.Userコンポーネントに透過するだけです.しかし、需要変動が必要な場合には、Linkコンポーネントを更新する必要があるので、Reactを使用することができる.Childrenの方法、すなわちslotの方法でコンポーネントを組み合わせます.
const Page = () => {
    return (
        
) } const Link = () => { return (
) } const User = () => { return (
) } const data = {name: 'lee'} const App = () => { return ( ) }

这种对组件的控制反转减少了在你的应用中要传递的 props 数量,这在很多场景下会使得你的代码更加干净,使你对根组件有更多的把控。但是,这并不适用于每一个场景:这种将逻辑提升到组件树的更高层次来处理,会使得这些高层组件变得更复杂,并且会强行将低层组件适应这样的形式,这可能不会是你想要的。而且你的组件并不限制于接收单个子组件。你可能会传递多个子组件,甚至会为这些子组件(children)封装多个单独的“接口(slots)”.

这种模式足够覆盖很多场景了,在这些场景下你需要将子组件和直接关联的父组件解耦。如果子组件需要在渲染前和父组件进行一些交流,你可以进一步使用 render props。

但是,有的时候在组件树中很多不同层级的组件需要访问同样的一批数据。Context 能让你将这些数据向组件树下所有的组件进行“广播”,所有的组件都能访问到这些数据,也能访问到后续的数据更新。使用 context 的通用的场景包括管理当前的 locale,theme,或者一些缓存数据,这比替代方案要简单的多。

Context API之React.createContext

const MyContext = React.createContext(defaultValue);

Contextオブジェクトを作成します.ReactがこのContextオブジェクトを購読したコンポーネントをレンダリングすると、このコンポーネントは、コンポーネントツリーの最も近い一致するProviderから現在のcontext値に読み出されます.defaultValueパラメータは、コンポーネントが置かれているツリーにProviderが一致していない場合にのみ有効です.これは、Providerパッケージコンポーネントを使用せずにコンポーネントをテストするのに役立ちます.注意:undefinedをProviderのvalueに渡すと、消費コンポーネントのdefaultValueは有効になりません.
Context APIのReact.Provider

各Contextオブジェクトは、消費コンポーネントがcontextの変更を購読できるProvider Reactコンポーネントを返します.
Providerはvalue属性を受信し、消費コンポーネントに渡す.1つのProviderは、複数の消費コンポーネントと対応することができます.複数のProviderをネストして使用することもでき、内側のレイヤは外側のデータを上書きします.
Providerのvalueの値が変化すると、その内部のすべての消費コンポーネントが再レンダリングされます.Providerおよびその内部consumerコンポーネントは、shouldComponentUpdate関数に限定されないため、consumerコンポーネントは、その祖先コンポーネントが更新を終了した場合でも更新することができる.
新旧値検出により変化を決定し,Object.isと同様のアルゴリズムを用いた.valueにオブジェクトが渡されると、contextがリファレンスID(reference identity)を使用してレンダリングのタイミングを決定するため、providerの親コンポーネントが再レンダリングされるとconsumersコンポーネントで予期せぬレンダリングがトリガーされるトラップがある可能性があります.たとえば、Providerが再レンダリングされるたびに、valueプロパティが常に新しいオブジェクトに割り当てられているため、次のコードは次のconsumersコンポーネントをすべて再レンダリングします.
class App extends React.Component {
  render() {
    return (
              
      
    );
  }
}

これを防止するために、valueステータスを親ノードのstateに上げます.
import React, {useState} from 'react
const App = () => {
  const [value, setValue]=useState({something: ''})

  render() {
    return (
      
        
      
    );
  }
}

Context APIのReact.Consumer

  {value => /*    context      */}

ここで、Reactコンポーネントはcontext変更に購読することもできます.これにより、関数コンポーネントでcontextの購読を完了できます.
これは関数をサブ要素(function as a child)として必要とする.この関数は現在のcontext値を受信し、Reactノードを返します.関数に渡されるvalueの値は、このcontextに最も近いProviderが提供するvalueの値に等しい.対応するProviderがない場合、valueパラメータは、createContext()に渡されるdefaultValueに等しい.
Context APIのReact.Consumercontextオブジェクトは、displayNameというpropertyを受け取り、タイプは文字列です.React DevToolsは、この文字列を使用してcontextが表示する内容を決定します.
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
 // "MyDisplayName.Provider"   DevTools  
 // "MyDisplayName.Consumer"   DevTools  

動的Context
React.createContext();ダイナミック値をバインドします.
ネストされたコンポーネントでContextを更新する:コンポーネントツリーにネストされた深いコンポーネントからcontextを更新する必要があります.このシーンでは、contextを介して関数を渡し、consumersコンポーネントがcontextを更新することができます.
//       createContext               (consumers)     !
export const ThemeContext = React.createContext({
  theme: themes.dark,  toggleTheme: () => {},});

複数のContextを消費する:contextが迅速に再レンダリングされるように、Reactは各consumersコンポーネントのcontextをコンポーネントツリー内で個別のノードにする必要がある.2つ以上のcontext値が頻繁に使用される場合は、これらの値を提供するために、独自のレンダリングコンポーネントを別途作成することを考慮する必要があります.
// Theme context,    theme   “light”  
const ThemeContext = React.createContext('light');

//      context
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;

    //      context    App   
    return (
      
        
          
        
      
    );
  }
}

function Layout() {
  return (
    
); } // context function Content() { return ( {theme => ( {user => ( )} )} ); }

これがContexに関する内容です...