【问题标题】:Call child hook function from parent using refs使用 refs 从父级调用子挂钩函数
【发布时间】:2019-12-31 19:23:24
【问题描述】:

我正在切换到使用 Hooks 构建组件,我正在努力使用 useRef() 设置参考

父级(引用目前仅添加到一个组件,因为我想确保在将功能扩展到其他组件之前它可以正常工作)

export default function UserPanels({ selected_client } ) {
    const classes = useStyles();
    const [value, setValue] = useState(0);
    const container = useRef( null );

    function handleChange(event, newValue) {
        setValue(newValue);
        container.current.displayData();
    }

    return (
        <div className={classes.root}>
            <UserTabs
                value={value}
                onChange={handleChange}
                indicatorColor="primary"
                textColor="primary"
                variant="fullWidth"
                aria-label="full width tabs example"
            >
                <Tab label='Service User' {...a11yProps(0)} />
                <Tab label='Care Plan' {...a11yProps(1)} />
                <Tab label='Contacts' {...a11yProps(2)} />
                <Tab label='Property' {...a11yProps(3)} />
                <Tab label='Schedule' {...a11yProps(4)} />
                <Tab label='Account' {...a11yProps(5)} />
                <Tab label='Invoices' {...a11yProps(6)} />
                <Tab label='Notes' {...a11yProps(7)} />
                <Tab label='eMAR' {...a11yProps(8)} />
            </UserTabs>
            <TabPanel value={value} index={0}>
                <UserDetailsContainer
                    selected_client={ selected_client }
                />
            </TabPanel>
            <TabPanel value={value} index={1}>
                Care Plan
            </TabPanel>
            <TabPanel value={value} index={2}>
                <ContactsContainer
                    ref={ container }
                    selected_client={ selected_client }
                />
            </TabPanel>
            <TabPanel value={value} index={3}>
                Property
            </TabPanel>
            <TabPanel value={value} index={4}>
                Schedule
            </TabPanel>
            <TabPanel value={value} index={5}>
                Account
            </TabPanel>
            <TabPanel value={value} index={6}>
                Invoices
            </TabPanel>
            <TabPanel value={value} index={7}>
                Notes
            </TabPanel>
            <TabPanel value={value} index={8}>
                eMAR
            </TabPanel>
        </div>
    );
}

孩子:

export default function ContactsContainer( props ) {
    const [ state, setState ] = useState({
        contact_records: contacts,
        data_ready: true
    });

    function displayData() {
        console.log( 'display time' );
    }

    if ( !state.data_ready ) return null

    return (
        <>
            {
                state.contact_records.map( ( contact ) => {
                    return <ContactRecord contact={ contact } />
                } )
            }
        </>
    )
}

基本上,我正在尝试从父函数调用子函数,但 ref.current 的计算结果为 null,当调用 handleChange() 时,我收到错误 container.current is null 并且我经常看到错误 Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

请注意,我已经测试过forwardRef

<ContactsContainer
    ref={ container }
    selected_client={ selected_client }
 />

而且,虽然这消除了错误,但它并没有解决问题。我从来没有遇到过将 refs 与类组件一起使用的问题,但我似乎在这里遗漏了一些东西。

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    首先,不要过度使用refsreact doc)。你不能通过直接调用它的函数来控制你的子组件(老实说你不能用函数组件来做到这一点)。

    如果您需要在子组件中显示某些内容,则必须在父组件中准备数据并通过道具传递该数据。孩子应该尽可能简单。他们应该得到道具并显示一些数据。

    在父母中:

    const [value, setValue] = useState(0);
    const [time, setTime] = useState(null);
    function handleChange(event, newValue) {
        setValue(newValue);
        setTime('display time');
    }
    
    return (
        ....
        <ContactsContainer
            time={time}
            selected_client={ selected_client }
         />
        ....
    )
    

    如果您需要在 props 更改时在您的孩子中产生一些副作用(例如进行 HTTP 调用、调度 Redux 操作),则必须使用 useEffect 钩子。

    在父母中:

    <ContactsContainer
        value={value}
        selected_client={ selected_client }
     />
    

    在孩子中:

    useEffect(() => {
      console.log('display time action');
    }, [props.value]);
    
    

    【讨论】:

    • 所以这通过点击匹配子索引的标签(索引)来工作。因此,如果我要将selected_index 传递给每个孩子,并且当selected_index 更改时,检查它是否与孩子匹配并显示一些数据,如果为真,那将是更好的选择?
    • @AdamRoberts 否。显示一些数据不是副作用。如果只需要显示数据,则必须在父组件中准备好,并通过 props 传递给子组件。我已经更新了答案。
    • 数据是从child生成的,但是否显示由parent决定。很难解释,但现在一切都整理好了 - 你的原始答案让我越过了界限,谢谢:)
    【解决方案2】:

    您可以将 ref 作为道具传递:

    // ...
    const infoRef=useRef(null)
    useEffect(()=>{
        if(infoRef.current) infoRef.current()
    },[])
    return <ChildComponent infoRef={infoRef} />
    

    然后在孩子中:

    useEffect(()=>{
        infoRef.current=childFunctionToExecuteInParent
    },[])
    

    【讨论】:

      猜你喜欢
      • 2019-12-14
      • 2020-01-22
      • 1970-01-01
      • 2020-05-11
      • 1970-01-01
      • 2020-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多