[解決済み] render関数の外側でReact Contextにアクセスする
質問
Reduxの代わりに新しいReact Context APIを使って新しいアプリを開発しているのですが、以前は
Redux
で、例えばユーザーのリストを取得する必要があるときは、単純に
componentDidMount
でアクションを呼び出すだけですが、React Context ではアクションはレンダー関数の中にある Consumer の中にあります。つまり、レンダー関数が呼び出されるたびに、ユーザーリストを取得するためにアクションが呼び出されます。
では、どうすれば一度だけ私のアクションを呼び出すことができるでしょうか。
componentDidMount
のように一度だけ呼び出すことはできますか?
例として、このコードを見てください。
をラップしているとします。
Providers
を一つのコンポーネントにまとめているとします。
import React from 'react';
import UserProvider from './UserProvider';
import PostProvider from './PostProvider';
export default class Provider extends React.Component {
render(){
return(
<UserProvider>
<PostProvider>
{this.props.children}
</PostProvider>
</UserProvider>
)
}
}
そして、このProviderコンポーネントを、以下のように、すべてのアプリを包むように配置します。
import React from 'react';
import Provider from './providers/Provider';
import { Router } from './Router';
export default class App extends React.Component {
render() {
const Component = Router();
return(
<Provider>
<Component />
</Provider>
)
}
}
さて、例えば私のユーザービューでは、次のようになります。
import React from 'react';
import UserContext from '../contexts/UserContext';
export default class Users extends React.Component {
render(){
return(
<UserContext.Consumer>
{({getUsers, users}) => {
getUsers();
return(
<h1>Users</h1>
<ul>
{users.map(user) => (
<li>{user.name}</li>
)}
</ul>
)
}}
</UserContext.Consumer>
)
}
}
私が欲しいのはこれです。
import React from 'react';
import UserContext from '../contexts/UserContext';
export default class Users extends React.Component {
componentDidMount(){
this.props.getUsers();
}
render(){
return(
<UserContext.Consumer>
{({users}) => {
getUsers();
return(
<h1>Users</h1>
<ul>
{users.map(user) => (
<li>{user.name}</li>
)}
</ul>
)
}}
</UserContext.Consumer>
)
}
}
しかし、もちろん、上の例では
getUsers
がUsers view propsに存在しないからです。もしこれが可能なら、正しい方法は何でしょうか?
どのように解決するのですか?
EDITです。
でのreact-hooksの導入により
v16.8.0
を利用することで、関数型コンポーネントでコンテキストを利用することができます。
useContext
フック
const Users = () => {
const contextValue = useContext(UserContext);
// rest logic here
}
EDITです。
バージョンから
16.6.0
になりました。ライフサイクルメソッドでコンテキストを利用するには
this.context
のように
class Users extends React.Component {
componentDidMount() {
let value = this.context;
/* perform a side-effect at mount using the value of UserContext */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* render something based on the value of UserContext */
}
}
Users.contextType = UserContext; // This part is important to access context values
バージョン16.6.0以前は、次のような方法で行うことができました。
ライフサイクルメソッドで Context を使用するには、次のようにコンポーネントを記述します。
class Users extends React.Component {
componentDidMount(){
this.props.getUsers();
}
render(){
const { users } = this.props;
return(
<h1>Users</h1>
<ul>
{users.map(user) => (
<li>{user.name}</li>
)}
</ul>
)
}
}
export default props => ( <UserContext.Consumer>
{({users, getUsers}) => {
return <Users {...props} users={users} getUsers={getUsers} />
}}
</UserContext.Consumer>
)
一般的には、アプリで1つのコンテキストを維持し、それを再利用するために、上記のログインをHOCでパッケージ化することは理にかなっています。次のように書くことができます。
import UserContext from 'path/to/UserContext';
const withUserContext = Component => {
return props => {
return (
<UserContext.Consumer>
{({users, getUsers}) => {
return <Component {...props} users={users} getUsers={getUsers} />;
}}
</UserContext.Consumer>
);
};
};
といった具合に使うことができます。
export default withUserContext(User);
関連
-
[解決済み】無効な設定オブジェクトです。APIスキーマと一致しない設定オブジェクトを使用してWebpackが初期化されました。
-
[解決済み】React Propsが定義されていません。
-
[解決済み] react nativeで関数だらけのヘルパーファイルを作成する方法は?
-
[解決済み] react.jsで複数のモジュールをエクスポートする
-
[解決済み] componentWillReceivePropsライフサイクルメソッドはいつ使用するのですか?
-
[解決済み] React QueryとReduxの主な違いは何ですか?
-
[解決済み] Reactルータを使ったプログラムによるナビゲーション
-
[解決済み] React JSX内のループ
-
[解決済み] Reactのこの3つの点は何をするところなのでしょうか?
-
[解決済み] Reactコンポーネント外でのクリックを検出する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】<Router>の外側で<Link>を使用してはならない
-
[解決済み】React 17で動作するEnzymeアダプターはどれですか?
-
[解決済み】Warning.Itが表示されるのはなぜですか?Functions are not valid as a React child?
-
[解決済み] Jestの `beforeEach` グローバルは何のためにあるのですか?
-
[解決済み] reactでonloadを使うには?
-
[解決済み] react jsでウィンドウを開くイベントを処理するにはどうすればよいですか?
-
[解決済み] React TypeScriptで作業しているときに、Jestが予期しないトークンに遭遇した
-
[解決済み] プロップ `history` は `Router` で必須とマークされているが、その値は `undefined` である。
-
[解決済み] react-navigation v5を使ったreact-nativeアプリのAppNavigatorの構文を更新する。
-
[解決済み] React QueryとReduxの主な違いは何ですか?