Open14
typescriptネタ
カスタムフックのパターン
- カウンタータイプ
- 操作を公開する、任意のイベント、コールバックを渡して更新させる
- APIタイプ
- 操作公開しない、内部で完結させる
- useEffect内に各理由は、基本的にコンポーネントもカスタムフックも トップレベルの関数は、stateが変化すると、呼び出されてしまう。これを防ぐために初回のみ何かしたい場合に、useEffectを使用する
stateが紐づけられていると、何か変化があった場合にコンポーネント内のロジックは毎回実行される
Refを使って子要素のフォームをクリックしたことにする
function ParentComponent() {
const myRef = useRef<HTMLFormElement>(null);
return (
<>
<p>子要素のフォームを呼び出し</p>
<button
onClick={() => {
myRef.current?.submit();
}}
>
call ref
</button>
<ChildComponent refObject={myRef} />
</>
);
}
type ChildComponentProps = {
refObject: RefObject<HTMLFormElement>;
};
//
function ChildComponent(props: ChildComponentProps) {
return (
<>
<Form ref={props.refObject} method="GET" action="/hoge"></Form>
</>
);
}
forwardRefは何か?
どうやらrefはカスタムコンポーネント(関数型には)つかえないようだ。
カスタムコンポーネントにはfowardrefを用いるみたい。
参照するためのラッパーオブジェクト
プロパティ:レンダー関数
〈プロパティ〉というのが理解できてなかった
type RefPageProps = {
ref: RefObject<HTMLInputElement>;
};
type RefPageProps = {
inputRef: RefObject<HTMLInputElement>;
};
既存のrefプロパティと認識されておかしくなっていた。
refプロパティは全てのコンポーネントに最初からあるものと認識する。
全てのコンポーネント?にはrefというフックが付いているイメージ
import React, { useRef, RefObject } from "react";
import { Form } from "react-router-dom";
function RefPage() {
return (
<>
<Parent />
</>
);
}
function Parent() {
const formRef = useRef<HTMLFormElement>(null);
const onClick = () => {
formRef.current?.submit();
};
return (
<>
<p>parent</p>
<button onClick={onClick}>子要素Submit</button>
<Child formRef={formRef} />
</>
);
}
type RefPageProps = {
formRef: RefObject<HTMLFormElement>;
};
function Child(props: RefPageProps) {
return (
<>
<form ref={props.formRef}>
<input name={"value1"} />
</form>
</>
);
}
export default RefPage;
サンプル更新
inputのvalueに値を設定すると、onChangeを設定しろと警告がでる。
valueを設定すると固定になってしまうようだ。
import React, { useRef, RefObject, forwardRef } from "react";
import { Form } from "react-router-dom";
// 参照可能な独自コンポーネント(例フォーム)
const FormRef = (props: any, ref: any) => {
// onChangeはエラー防止のため
// 渡されたRefをformに紐づけ
return (
<>
<form ref={ref} {...props}>
<input name={"key"} value="abc" onChange={() => {}} />
</form>
</>
);
};
// 独自コンポーネント参照可能にするためラップ
const FowardForm = forwardRef(FormRef);
function FowardRefPage() {
const ref = useRef<HTMLFormElement>(null);
const onClick = () => {
ref.current?.submit(); // ref操作
};
return (
<>
<FowardForm ref={ref}></FowardForm>
<button type="button" onClick={onClick}>
ref submit
</button>
</>
);
}
export default FowardRefPage;
reactのFowardRefの型定義を見る。
関数型コンポーネントの場合はFowardRefの型が省略されているので分かりづらい。
・refとpropsの引数を持ち、ReactNode(コンポーネント)を返せばよいこと。
・ただし、propsはデフォルト引数が設定されているので考えなくて良い。
function forwardRef<T, P = {}>(
render: ForwardRefRenderFunction<T, P>,
): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;
interface ForwardRefRenderFunction<T, P = {}> {
(props: P, ref: ForwardedRef<T>): ReactNode;
displayName?: string | undefined;
defaultProps?: never | undefined;
propTypes?: never | undefined;
}