带有自定义组件和自定义挂钩的 forwardRef
forwardRef with custom component and custom hook
编辑:为提高可读性而进行的小改动。
我是新来的反应者,我可能已经陷入困境,但无论如何我都会继续..
我有一个登录组件,当用户单击提交时输入元素失去焦点 and/or 时,我想在其中向用户提供反馈。
我知道我用 useState
实现了类似的行为,但为了教育我正在尝试 useRef
。
我在 LoginForm.js
中收到 inputRef
未定义读取的类型错误。所以当 validateInput
被调用时 inputRef
没有被赋值。谁能帮我弄清楚为什么会这样,是否有解决办法?
LoginForm.js:
import useInput from '../../hooks/use-input';
import Input from '../../UI/Input/Input';
const LoginForm = () => {
const { inputRef, isValid } = useInput(value =>
value.includes('@')
);
return <Input ref={inputRef} />;
};
use-input.js(自定义挂钩):
const useInput = validateInput => {
const inputRef = useRef();
const isValid = validateInput(inputRef.current.value);
return {
inputRef,
isValid,
};
};
Input.js(自定义元素组件):
const Input = forwardRef((props, ref) => {
return <input ref={ref} {...props.input}></input>;
});
我看到的一个问题是,在 Input
组件中,您使用的是 props.input
,为什么?
const Input = forwardRef((props, ref) => {
return <input ref={ref} {...props}></input>;
});
您希望将发送的 props 分配给组件。
接下来,您正在做 value.includes('@')
,但您确定 value
不是 undefined
吗?
const { inputRef, isValid } = useInput(value =>
value && value.includes('@')
);
这将消除该错误的可能性。
解决 inputRef is undefined
的问题并不难解决。
之后,您将面临另一个问题。您正在使用 useRef
(不受控制)这一事实不会导致重新呈现,因此,如果您更新输入内容,isValid
将不会更新其值。
Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. (React Docs)
这是个人笔记,但我发现不受控制的组件通常很难 maintain/scale/...,而且 ref 通常不打算做这种事情。 (是的,是的,你有 react-form-hook
,它提供了一种使用不受控制的组件创建表单的方法,是的,它是高效的)。
同时,在我进一步研究这个问题的同时,我可以使用 useState
.
为您提供解决方案
const useInput = (validationRule, initialValue='') => {
const [value, setValue] = useState(initialValue)
const onChange = (e) => setValue(e.target.value)
const isValid = validationRule && validationRule(value)
return {
inputProps: {
value,
onChange
},
isValid
}
}
所以,在这里我们有一个函数,它有 2 个参数,validationRule
和 initialValue
(这是可选的,如果没有提供,将默认为文本)。
我们正在做基本的 value / onChange
事情,然后我们将这 2 个作为 inputProps
返回。此外,我们只是调用 validationRule
(之前,我们检查它是否存在并将其作为参数发送)。
使用方法:
export default function SomeForm() {
const { inputProps, isValid } = useInput((value) => value.includes('@'));
return <Input {...inputProps}/>;
}
以下部分我强烈反对。
这很糟糕,但目前,使用 refs 实现它的唯一方法是使用 useReducer
强制更新 onChange
.
例如:
const useInput = (validationRule) => {
const [, forceUpdate] = useReducer((p) => !p, true);
const inputRef = useRef();
const onChange = () => forceUpdate();
const isValid = validationRule && validationRule(inputRef.current?.value);
return {
inputRef,
isValid,
onChange
};
};
然后,用作:
export default function SomeForm() {
const { inputRef, onChange, isValid } = useInput((value) =>
value && value.includes("@")
);
console.log(isValid);
return <Input ref={inputRef} onChange={onChange} />;
}
编辑:为提高可读性而进行的小改动。
我是新来的反应者,我可能已经陷入困境,但无论如何我都会继续..
我有一个登录组件,当用户单击提交时输入元素失去焦点 and/or 时,我想在其中向用户提供反馈。
我知道我用 useState
实现了类似的行为,但为了教育我正在尝试 useRef
。
我在 LoginForm.js
中收到 inputRef
未定义读取的类型错误。所以当 validateInput
被调用时 inputRef
没有被赋值。谁能帮我弄清楚为什么会这样,是否有解决办法?
LoginForm.js:
import useInput from '../../hooks/use-input';
import Input from '../../UI/Input/Input';
const LoginForm = () => {
const { inputRef, isValid } = useInput(value =>
value.includes('@')
);
return <Input ref={inputRef} />;
};
use-input.js(自定义挂钩):
const useInput = validateInput => {
const inputRef = useRef();
const isValid = validateInput(inputRef.current.value);
return {
inputRef,
isValid,
};
};
Input.js(自定义元素组件):
const Input = forwardRef((props, ref) => {
return <input ref={ref} {...props.input}></input>;
});
我看到的一个问题是,在 Input
组件中,您使用的是 props.input
,为什么?
const Input = forwardRef((props, ref) => {
return <input ref={ref} {...props}></input>;
});
您希望将发送的 props 分配给组件。
接下来,您正在做 value.includes('@')
,但您确定 value
不是 undefined
吗?
const { inputRef, isValid } = useInput(value =>
value && value.includes('@')
);
这将消除该错误的可能性。
解决 inputRef is undefined
的问题并不难解决。
之后,您将面临另一个问题。您正在使用 useRef
(不受控制)这一事实不会导致重新呈现,因此,如果您更新输入内容,isValid
将不会更新其值。
Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. (React Docs)
这是个人笔记,但我发现不受控制的组件通常很难 maintain/scale/...,而且 ref 通常不打算做这种事情。 (是的,是的,你有 react-form-hook
,它提供了一种使用不受控制的组件创建表单的方法,是的,它是高效的)。
同时,在我进一步研究这个问题的同时,我可以使用 useState
.
const useInput = (validationRule, initialValue='') => {
const [value, setValue] = useState(initialValue)
const onChange = (e) => setValue(e.target.value)
const isValid = validationRule && validationRule(value)
return {
inputProps: {
value,
onChange
},
isValid
}
}
所以,在这里我们有一个函数,它有 2 个参数,validationRule
和 initialValue
(这是可选的,如果没有提供,将默认为文本)。
我们正在做基本的 value / onChange
事情,然后我们将这 2 个作为 inputProps
返回。此外,我们只是调用 validationRule
(之前,我们检查它是否存在并将其作为参数发送)。
使用方法:
export default function SomeForm() {
const { inputProps, isValid } = useInput((value) => value.includes('@'));
return <Input {...inputProps}/>;
}
以下部分我强烈反对。
这很糟糕,但目前,使用 refs 实现它的唯一方法是使用 useReducer
强制更新 onChange
.
例如:
const useInput = (validationRule) => {
const [, forceUpdate] = useReducer((p) => !p, true);
const inputRef = useRef();
const onChange = () => forceUpdate();
const isValid = validationRule && validationRule(inputRef.current?.value);
return {
inputRef,
isValid,
onChange
};
};
然后,用作:
export default function SomeForm() {
const { inputRef, onChange, isValid } = useInput((value) =>
value && value.includes("@")
);
console.log(isValid);
return <Input ref={inputRef} onChange={onChange} />;
}