web-dev-qa-db-ja.com

ReactのuseState()フックを使用してコンポーネント間で状態を共有することは可能ですか?

Reactの新しいフック機能を試していました。次の2つのコンポーネントがあると考えます(Reactフックを使用)-

const HookComponent = () => {
  const [username, setUsername] = useState('Abrar');
  const [count, setState] = useState();
  const handleChange = (e) => {
    setUsername(e.target.value);
  }

  return (
    <div>
      <input name="userName" value={username} onChange={handleChange}/>
      <p>{username}</p>
      <p>From HookComponent: {count}</p>
    </div>
  )
}


const HookComponent2 = () => {
  const [count, setCount] = useState(999);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

フックは、コンポーネント間でステートフルロジックを共有するという問題を解決すると主張していますが、HookComponentHookComponent2の間の状態は共有できないことがわかりました。たとえば、HookComponent2countの変更は、HookComponentの変更をレンダリングしません。

useState()フックを使用してコンポーネント間で状態を共有することは可能ですか?

18
Abrar

コンポーネントの状態を参照している場合、フックはコンポーネント間で共有するのに役立ちません。コンポーネントの状態は、コンポーネントに対してローカルです。状態がコンテキスト内にある場合、useContextフックが役立ちます。

基本的に、「コンポーネント間でステートフルロジックを共有する」というラインを誤解していると思います。ステートフルロジックは状態とは異なります。ステートフルロジックとは、状態を変更するものです。たとえば、componentDidMount()でストアにサブスクライブし、componentWillUnmount()でサブスクライブ解除するコンポーネント。このサブスクライブ/サブスクライブ解除動作はフックに実装でき、この動作を必要とするコンポーネントはフックを使用するだけです。

コンポーネント間で状態を共有する場合、さまざまな方法があり、それぞれにメリットがあります。

1.状態を上げる

2つのコンポーネントの共通の祖先コンポーネントまで状態を持ち上げます。

function Ancestor() {
    const [count, setCount] = useState(999);
    return <>
      <DescendantA count={count} />
      <DescendantB count={count} />
    </>;
  }

この状態共有のアプローチは、従来の状態の使用方法と根本的には異なりません。フックは、コンポーネントの状態を宣言するための異なる方法を提供するだけです。

2.コンテキスト

子孫がコンポーネント階層の深すぎて、あまり多くのレイヤーに状態を渡したくない場合は、 Context API を使用できます。

子コンポーネント内で活用できるuseContextフックがあります。

3.外部状態管理ソリューション

ReduxやMobxなどの状態管理ライブラリ。状態はReactの外部のストアに保存され、コンポーネントはストアに接続/サブスクライブして更新を受信できます。

28
Yangshun Tay

doc 状態:

ReactからuseStateフックをインポートします。これにより、関数コンポーネントのローカル状態を保持できます。

状態をコンポーネント間で共有できることは言及していません。useStateフックは、1つの命令で状態フィールドとその対応するセッターを宣言するためのより迅速な方法を提供するだけです。

3
Karim

これを正確に実行できるhooksyを作成しました- https://github.com/pie6k/hooksy

import { createStore } from 'hooksy';

interface UserData {
  username: string;
}

const defaultUser: UserData = { username: 'Foo' };

export const [useUserStore] = createStore(defaultUser); // we've created store with initial value.
// useUserStore has the same signature like react useState hook, but the state will be shared across all components using it

そして、後で任意のコンポーネントで

import React from 'react';

import { useUserStore } from './userStore';

export function UserInfo() {
  const [user, setUser] = useUserStore(); // use it the same way like useState, but have state shared across any component using it (eg. if any of them will call setUser - all other components using it will get re-rendered with new state)

  function login() {
    setUser({ username: 'Foo' })
  }

  return (
    <div>
      {!user && <strong>You're logged out<button onPress={login}>Login</button></strong>}
      {user && <strong>Logged as <strong>{user.username}</strong></strong>}
    </div>
  );
}
1
pie6k

状態をHookComponent1およびHookComponent2の祖先コンポーネントに引き上げる必要があります。これが以前の状態の共有方法であり、最新のフックAPIはそれについて何も変更しません。

1
Yongzhi

フックでは、直接は不可能です。反応しやすい状態を確認することをお勧めします。 https://github.com/solkimicreb/react-easy-state

私は大きなアプリでそれを使用し、それは魅力のように動作します。

0
Marcel Ennix