反应子组件失去对Change的关注

问题描述 投票:0回答:1

我有一个父组件 MasterList,我需要打开一个模式弹出窗口,其中包含一个表单,用于根据 activeTab(指定或组织)有条件地添加指定和组织,因为我有两个用于指定和组织的网格。 我有用于模态弹出窗口的 ModalContainer 组件,该组件将输入组件作为子组件来添加新的主数据(名称或组织)。 所以这里的输入组件有输入字段当我尝试在输入字段中输入时它会失去焦点。 我知道这是由于“组件的重新渲染”而发生的,这就是它失去焦点的原因,但我想要一个解决方案来解决它。 或者在这种情况下使用的最佳解决方案。 我提供下面的 MasterLst 组件、ModalContainer、Input 组件。

MasterLst 组件:

const MasterList = () => { const dispatch = useDispatch(); const navigate = useNavigate(); const [addMasterData, setAddMasterData] = useState({ designation: { value: '', error: '' }, description: { value: '', error: '' }, organization: { value: '', error: '' }, }); const [addDesignationData, setAddDesignationData] = useState({ designation: { value: '', error: '' }, description: { value: '', error: '' }, }); const [addOrganizationData, setAddOrganizationData] = useState({ organization: { value: '', error: '' }, }); const [activeTab, setActiveTab] = useState('Designation'); const [showModal, setShowModal] = useState(false); const { mastersByType, loading: masterLoading } = useSelector((state) => state.mastersByType); const { credentials } = useSelector((state) => state.login); const resetaddMasterData = useCallback(() => { setAddMasterData({ designation: { value: '', error: '' }, description: { value: '', error: '' }, organization: { value: '', error: '' }, }); }, []); const resetAddDesignationData = useCallback(() => { setAddDesignationData({ designation: { value: '', error: '' }, description: { value: '', error: '' }, }); }, []); const resetAddOrganizationData = useCallback(() => { setAddOrganizationData({ organization: { value: '', error: '' }, }); }, []); const onMasterDataChange = useCallback( (event) => { const { name, value } = event.target; setAddMasterData((prevData) => ({ ...prevData, [name]: { value, error: '' }, })); }, [setAddMasterData] ); const onDesignationChange = useCallback( (event) => { const { name, value } = event.target; setAddDesignationData((prevData) => ({ ...prevData, [name]: { value, error: '' }, })); }, [setAddDesignationData] ); const onOrganizationChange = useCallback( (event) => { const { name, value } = event.target; setAddOrganizationData((prevData) => ({ ...prevData, [name]: { value, error: '' }, })); }, [setAddOrganizationData] ); const handleTabClick = useCallback( (tab) => { setActiveTab(tab); }, [setActiveTab] ); const inputRef = useRef(null); useEffect(() => { if (showModal) { inputRef.current && inputRef.current.focus(); } }, [showModal]); useEffect(() => { if (credentials) { const data = { masterType: activeTab === 'Designation' ? 'Designation' : 'Organization', }; dispatch(getMastersByType(data)); } }, [activeTab, dispatch, credentials]); return ( <PageContainer> <div className={styles.topContainer}> <div className={styles.left}> <label>Master List</label> </div> <div className={styles.right}> <img src="./images/scenario.png" /> </div> </div> <div className={styles.mainContainer}> <div className={styles.mainTopContainer}> <div className={styles.mainTopLeft}> <div className={styles.designationsContainer}> <div className={styles.designationsTop} onClick={() => handleTabClick('Designation')} > <label style={{ color: activeTab === 'Designation' ? 'var(--primary)' : 'var(--input_label)' }} > Designations </label> </div> <div className={styles.designationsBottom} style={{ backgroundColor: activeTab === 'Designation' ? 'var(--primary)' : 'var(--input_label)' }} ></div> </div> <div className={styles.organizationsContainer} onClick={() => handleTabClick('Organization')} > <div className={styles.organizationsTop}> <label style={{ color: activeTab === 'Organization' ? 'var(--primary)' : 'var(--input_label)' }} > Organizations </label> </div> <div className={styles.organizationsBottom} style={{ backgroundColor: activeTab === 'Organization' ? 'var(--primary)' : 'var(--input_label)' }} ></div> </div> </div> <div className={styles.mainTopRight}> <Button onClick={() => { setShowModal(true); }} > Add New </Button> </div> </div> <div className={styles.mainBottomContainer}> {/* Master List Table:: start */} <div className={styles.mainTableContainer}> <table className={styles.table_content}> <thead> {activeTab === 'Designation' ? ( <tr> <th></th> <th>#</th> <th>Designation</th> <th>Description</th> <th>Date Created</th> <th>Scenario</th> <th>Status</th> <th></th> </tr> ) : ( <tr> <th></th> <th>#</th> <th>Organization</th> <th>Member Users</th> <th>Date Created</th> <th>Games Played</th> <th>Status</th> <th></th> </tr> )} </thead> <tbody> {activeTab === 'Designation' ? ( mastersByType && mastersByType.success && mastersByType.data && JSON.parse(mastersByType.data)?.map((master, index) => ( <tr key={index}> <td> <Checkbox /> </td> <td>{index + 1}</td> <td>{master.MasterDisplayName}</td> <td>Description</td> <td>1 Jan 2024</td> <td>5</td> <td>Active</td> <td> <div className={styles.actions}> <div className={styles.circleSvg}> <svg> <use xlinkHref="sprite.svg#edit_icon" /> </svg> </div> <div className={styles.circleSvg}> <svg> <use xlinkHref="sprite.svg#delete_icon" /> </svg> </div> </div> </td> </tr> )) ) : ( mastersByType && mastersByType.success && mastersByType.data && JSON.parse(mastersByType.data)?.map((master, index) => ( <tr key={index}> <td> <Checkbox /> </td> <td>{index + 1}</td> <td>{master.MasterDisplayName}</td> <td>25</td> <td>1 Jan 2024</td> <td>5</td> <td>Active</td> <td> <div className={styles.actions}> <div className={styles.circleSvg}> <svg> <use xlinkHref="sprite.svg#edit_icon" /> </svg> </div> <div className={styles.circleSvg}> <svg> <use xlinkHref="sprite.svg#delete_icon" /> </svg> </div> </div> </td> </tr> )) ) } </tbody> </table> </div> {/* Master List Table:: end */} </div> </div> {/* Modal Container :: start*/} {showModal && ( <ModalContainer> <div className="modal_content"> <div className="modal_header"> <div> {activeTab === 'Designation' ? 'Add Designation' : 'Add Organization'} </div> <div> <svg className="modal_crossIcon" onClick={() => { setShowModal(false); // resetAddGroupData(); }} > <use xlinkHref={"sprite.svg#crossIcon"} /> </svg> </div> </div> <div className={styles.modalInputContainer}> {activeTab === 'Designation' ? ( <div> <Input type="text" customStyle={{ marginTop: '1rem', }} value={addDesignationData.designation.value} name={"designation"} placeholder="Designation Name" onChange={onDesignationChange} /> <Input type="text" customStyle={{ marginTop: '1rem', }} value={addDesignationData.description.value} name={"description"} placeholder="Description" textAreaStyleClass={styles.textAreaStyleClass} onChange={onDesignationChange} textArea /> </div> ) : ( <div> <Input type="text" customStyle={{ marginTop: '1rem', }} value={addOrganizationData.organization.value} name={"organization"} placeholder="Organization Name" onChange={onOrganizationChange} /> </div> ) } </div> <div className="modal_buttonContainer"> <Button buttonType={"cancel"} onClick={() => { setShowModal(false); // resetAddGroupData(); }} > Cancel </Button> <Button customStyle={{ marginLeft: "1rem", }} // onClick={onAddGroup} > Add </Button> </div> </div> </ModalContainer> )} {/* Modal Container :: end*/} </PageContainer> ); }; export default MasterList;
ModalContainer 组件:

import React, { useState } from "react"; import ReactDOM from "react-dom"; import styles from "./modal.module.css"; const ModalContainer = ({ children }) => { const modalRoot = document.getElementById("modal-root"); const modalElement = document.createElement("div"); modalRoot.appendChild(modalElement); return ReactDOM.createPortal( <div className={styles.container}>{children}</div>, modalElement ); }; export default ModalContainer;
输入组件:

import style from "./input.module.css"; const Input = ({ textArea, type, customStyle, label, name, disabled = false, value = "", labelStyle = "", textAreaStyleClass, onChange = () => {}, ref, ...props }) => { return ( <div style={customStyle} className={style.formGroup}> <label className={labelStyle}>{label}</label> {textArea ? ( <textarea disabled={disabled} name={name} value={value} className={`${style.formControl} ${textAreaStyleClass}`} placeholder={label} {...props} onChange={onChange} /> ) : ( <input disabled={disabled} type={type} name={name} value={value} className={style.formControl} placeholder={label} ref={ref} {...props} onChange={onChange} /> )} </div> ); }; export default Input;
我尝试使用
autoFocus

useRef
,但它们都不起作用。 我是 React 新手,不知道如何解决这个问题。
我的一位同事建议在与组件相同的文件中的模态内创建容器,但不要在同一文件(即 MasterList)中导出和使用。
任何建议、解决方案都会有帮助。

reactjs redux react-hooks state react-state-management
1个回答
0
投票
div

并将其附加到每个渲染上的

#modal-root
。这使得
createPortal
接收新元素,并卸载以前的内容并安装新内容。像这样的东西应该可以解决这个问题:
const ModalContainer = ({ children }) => {
        const element = useRef()  
        // here the element is created only once
        if (!element.current) element.current = document.createElement('div')
    
        useLayoutEffect(() => {
            const target = document.getElementById('modal-root')
            // element is attached to the target only once
            target.appendChild(el.current)
            return () => {
                target.removeChild(element.current)
            }
        }, [])
    
        return createPortal(children, element.current)
     }

© www.soinside.com 2019 - 2024. All rights reserved.