簡単な例を作成しました https://codesandbox.io/s/4zq852m7j 。
ご覧のとおり、リモートソースからいくつかのデータをフェッチしています。テキストフィールド内の値として戻り値を使用したいと思います。
const useFetch = () => {
const [value, setValue] = useState("");
useEffect(
async () => {
const response = await fetch("https://httpbin.org/get?foo=bar");
const data = await response.json();
setValue(data.args.foo);
},
[value]
);
return value;
};
ただし、useState
関数内で値を使用することはできません。 useState
は最初のレンダリングでのみデフォルト値を使用すると思います。最初にレンダリングするとき、値は非同期であるため、明らかに設定されていません。テキストフィールドの値はbar
である必要がありますが、空です。
function App() {
const remoteName = useFetch();
// i want to see the remote value inside my textfield
const [name, setName] = useState(remoteName);
const onChange = event => {
setName(event.target.value);
};
return (
<div className="App">
<p>remote name: {remoteName}</p>
<p>local name: {name}</p>
<input onChange={onChange} value={name} />
</div>
);
}
リモートから値を取得した後、ローカルで値を変更できるようにしたいと思います。
何か案は?
これは、クラスコンポーネントで非同期的に初期状態を設定する場合とまったく同じです。
state = {};
async componentDidMount() {
const response = await fetch(...);
...
this.setState(...);
}
非同期で取得された状態は、初期レンダリング中に使用できません。関数コンポーネントは、クラスコンポーネントと同じ手法を使用する必要があります。つまり、状態に依存する子を条件付きでレンダリングします。
return name && <div className="App">...</div>;
このように、useFetch
が独自の状態を持つ理由はなく、コンポーネントとの共通の状態を維持できます( 例 ):
const useFetch = () => {
const [value, setValue] = useState("");
useEffect(
async () => {
const response = await fetch("https://httpbin.org/get?foo=bar");
const data = await response.json();
setValue(data.args.foo);
},
[] // executed on component mount
);
return [value, setValue];
};
function App() {
const [name, setName] = useFetch();
const onChange = event => {
setName(event.target.value);
};
return name && (
<div className="App">
<p>local name: {name}</p>
<input onChange={onChange} value={name} />
</div>
);
}