如何修改传入CustomInput的Form.Control的type属性实现密码显隐功能
问题根源
你直接将已实例化的<Form.Control> React元素作为prop传入CustomInput,React元素是不可变对象,无法直接修改其属性,所以你直接给formControl.type赋值的写法不会生效。你之前在父组件定义状态绑定type也不生效,是因为父组件的状态和CustomInput内部的状态完全独立,没有关联。
正确实现方案
1. 修改CustomInput.js
使用React.cloneElement克隆传入的formControl元素,动态覆盖type属性即可,同时不要直接修改传入的rightAddon prop(props为只读,直接修改会引发副作用),改为生成新的配置对象:
import { Icon } from '../Icon' import { useState, cloneElement } from 'react' export const CustomInput = ({ formControl, rightAddon: rawRightAddon, passwordEye }) => { const [inputType, setInputType] = useState("password") const [showPassword, setShowPassword] = useState(false) const togglePasswordEye = () => { setInputType(prev => prev === 'text' ? 'password' : 'text') setShowPassword(prev => !prev) } // 生成右侧附加配置,不修改原始props const rightAddon = passwordEye ? { ...rawRightAddon, icon: showPassword ? 'eye' : 'eye-slash', onClick: togglePasswordEye, clickable: true } : rawRightAddon // 克隆输入框组件,密码模式下覆盖type属性 const processedFormControl = passwordEye ? cloneElement(formControl, { type: inputType }) : formControl return ( <div> {processedFormControl} {rightAddon && ( <span className={`password-eye ${passwordEye || rightAddon.clickable ? 'cursor-pointer' : ''}`} onClick={rightAddon.onClick}> <Icon name={rightAddon.icon} /> </span> )} </div> ) }
2. 修改LogIn.js
你不需要再在父组件维护密码显示相关的状态(inputType、showPassword、togglePasswordEye都可以删掉),直接按你期望的写法调用即可:
import Form from 'react-bootstrap/Form' import { CustomInput } from '../CustomInput' // 省略其他无关代码... <CustomInput passwordEye rightAddon={{icon: "eye"}} formControl={ <Form.Control className={`form-control form-control-lg ${errors.password ? 'input-error' : ''}`} placeholder="Enter your password" type="password" name="password" autoComplete="current-password" tabIndex={2} {...register("password", { required: "Password is required", minLength: { value: 6, message: "Password should be more than 6 characters" } })} /> } />
实现原理
React.cloneElement可以接收一个已有的React元素作为第一个参数,第二个参数传入需要覆盖的新props,返回一个合并了新属性的新元素,以此实现动态修改传入组件属性的需求。所有密码显隐的逻辑都封装在CustomInput内部,完全符合你仅添加passwordEye属性即可启用功能的目标。
内容的提问来源于stack exchange,提问作者tatoline
相关产品推荐
相关产品推荐

