【问题标题】:How to pass ref to children of children using array of refs React?如何使用 refs React 数组将 ref 传递给孩子的孩子?
【发布时间】:2021-08-20 19:16:48
【问题描述】:

我正在尝试将多次参考传递给孩子的孩子,但它不起作用。我有一个名为AvatarBuilder 的功能组件,它使用Avatars 组件。该组件呈现Avatar 组件的列表。这个想法是在 AvatarBuilder 中引用每个 Avatar 组件。

这里是sn-p总结的代码:

const AvatarBuilder = props => {
    ...
    // in this dummy example i would have 5 avatars
    const URLS=[1,2,3,4,5];
    const refs = URLS.map(item => ({ ref: React.createRef() }));
    return (
        <>
            <Avatars
                ref={refs}
                urlList={URLS}
            />
        </>
    );

const Avatars = React.forwardRef((props, ref) => {
    let urlList = props.urlList.map((url, index) => {
        return (
            <Avatar
                ref={ref[index].ref}
                url={url}
            />
        )
    })
    return (
        <ul className="Avatars" >
            {urlList}
        </ul>
    )
});

const Avatar = React.forwardRef((props, ref) => {
    return (
        <li className="Avatar">
            <img
                src={props.url}
                ref={ref}
            />
        </li>
    )
});

我收到以下警告,并且在安装所有组件后 refs 数组未更新。

index.js:1 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of `ForwardRef`.
    in h (at Avatar.js:11)
    in li (at Avatar.js:10)
    in ForwardRef (at Avatars.js:10)
    in ul (at Avatars.js:24)
    in ForwardRef (at AvatarBuilder.js:189)
    in AvatarBuilder (at App.js:19)
    in div (at App.js:14)
    in App (at src/index.js:9)
    in StrictMode (at src/index.js:8)

知道如何解决这个问题吗?谢谢!

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    对于函数式组件,您必须使用 useRef 而不是 React.createRef,因为将在渲染中创建一个新的 ref 实例。

    如果你使用 React.createRef,那么使用 useMemo 来记忆 refs

    const AvatarBuilder = props => {
        // in this dummy example i would have 5 avatars
        const URLS=[1,2,3,4,5];
        const refs = React.useMemo(() =>URLS.map(item => ({ ref: React.createRef() })), []); // create refs only once
        React.useEffect(() => {
           console.log(refs);
        },[])
        return (
                <Avatars
                    ref={refs}
                    urlList={URLS}
                />
        );
    }
    const Avatars = React.forwardRef((props, ref) => {
        let urlList = props.urlList.map((url, index) => {
            return (
                <Avatar
                    ref={ref[index].ref}
                    url={url}
                />
            )
        })
        return (
            <ul className="Avatars" >
                {urlList}
            </ul>
        )
    });
    
    const Avatar = React.forwardRef((props, ref) => {
        return (
            <li className="Avatar">
                <img
                    src={props.url}
                    ref={ref}
                />
            </li>
        )
    });
    
    ReactDOM.render(<AvatarBuilder/>, document.getElementById('app'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
    <div id="app"/>

    【讨论】:

    • 你不能在这种情况下使用useRef,因为它违反了钩子的基本规则,即它们应该始终以相同的顺序调用。如果URLS 发生变化(在这个人为的 示例中不会发生变化),那么useRef 将被调用不同的次数,并且组件将具有未定义的行为。
    【解决方案2】:

    试试这个。

    const AvatarBuilder = props => {
        ...
        // in this dummy example i would have 5 avatars
        const URLS=[1,2,3,4,5];
        const refs = URLS.map(item => React.createRef());
        return (
            <>
                <Avatars
                    refs={refs}
                    urlList={URLS}
                />
            </>
        );
    
    // you don't need to make it with `fowardRef()`
    const Avatars = (props) => {
        const {refs} = props;
        let urlList = props.urlList.map((url, index) => {
            console.log(url, index, typeof (index), ref);
            return (
                <Avatar
                    ref={refs[index]}
                    url={url}
                />
            )
        })
        return (
            <ul className="Avatars" >
                {urlList}
            </ul>
        )
    };
    
    const Avatar = React.forwardRef((props, ref) => {
        return (
            <li className="Avatar">
                <img
                    src={props.url}
                    ref={ref}
                />
            </li>
        )
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-10
      • 2016-03-19
      相关资源
      最近更新 更多