错误:功能组件不能具有引用。

时间:2020-07-08 08:01:11

标签: javascript reactjs react-hooks

我正在尝试转换class component to functional component。但出现此错误

功能组件不能具有引用。您是要使用React.forwardRef()吗?

使用class component

的示例

https://codesandbox.io/s/highlight-search-results-wqtlm?file=/src/components/Search/List.js

现在,我将list类组件更改为功能组件

https://codesandbox.io/s/funny-bird-dkfpi?file=/src/components/List.js

我的代码中断并给我下面的错误

功能组件不能具有引用。您是要使用React.forwardRef()吗?

请建议如何解决此错误

import React, { useEffect, useRef, useState} from 'react';
import User from './User';

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

const List = ({users})=>{
  const [focusedUser, setFocusedUser]  = useState(-1);
  const [scrollIntoView, setScrollIntoView]  = useState(false);
  const userRef = useRef();
  const prev = usePrevious({focusedUser});


  useEffect(()=>{
    if (
        focusedUser !== prev.focusedUser &&
        scrollIntoView
    ) {
      ensureFocusedItemVisible();
    }
  },[focusedUser])

  const ensureFocusedItemVisible =()=> {
     userRef.current &&
    userRef.current.scrollIntoView({
      behaviour: 'smooth',
      block: 'center'
    });
  }

  const handleKeyPress = e => {
    // scroll into view only on keyboard navigation
    setScrollIntoView( true );
    // up arrow
    if (e.keyCode === 38) {
      const fu = focusedUser <= 0 ? 0 : focusedUser - 1;
      setFocusedUser(fu);
    }
    // down arrow
    if (e.keyCode === 40) {
      const currentFocus = focusedUser;
      // if down key is pressed multiple times on last list item, keep last item highlighted
      const fu =
          currentFocus >= users.length - 1
              ? users.length - 1
              : currentFocus + 1;
      setFocusedUser(fu);
    }
  };

 const handleMouseEvent = id => {
    userRef.current && userRef.current.focus();
   setScrollIntoView(false);
   setFocusedUser(parseInt(id))
  };

  const listElements = users.map((user, index) => {
    const focused = index === focusedUser;
    return (
        <User
            divId={index}
            data={user}
            focused={focused}
            ref={focused && userRef}
            handleKeyPress={handleKeyPress}
            handleMouseEvent={handleMouseEvent}
        />
    );
  });

    return <div className="result-list">{listElements}</div>;
}

export default List;

1 个答案:

答案 0 :(得分:0)

您实际上有2个错误。

第一个在这里:

ref={focused && this.userRef}

第二个在这里:

const prev = usePrevious({ focusedUser });

useEffect(() => {
  if (focusedUser !== prev.focusedUser && scrollIntoView) {
    ensureFocusedItemVisible();
  }
}, [focusedUser]);

这是注释中带解释的修复程序:

import React, { useEffect, useRef, useState } from "react";
import User from "./User";

const List = ({ users }) => {
  const [focusedUser, setFocusedUser] = useState(-1);
  const [scrollIntoView, setScrollIntoView] = useState(false);
  const userRef = useRef();

  // You don't need to keep track of the previous value.
  // useEffect will be called on first render and whenever one of the values in the dependencies array changes
  // So it will run whenever the focusedUser changes
  useEffect(() => {
    if (scrollIntoView) {
      ensureFocusedItemVisible();
    }
  }, [focusedUser, scrollIntoView]);

  const ensureFocusedItemVisible = () => {
    userRef.current &&
      userRef.current.scrollIntoView({
        behaviour: "smooth",
        block: "center"
      });
  };

  const handleKeyPress = e => {
    // scroll into view only on keyboard navigation
    setScrollIntoView(true);
    // up arrow
    if (e.keyCode === 38) {
      const fu = focusedUser <= 0 ? 0 : focusedUser - 1;
      setFocusedUser(fu);
    }
    // down arrow
    if (e.keyCode === 40) {
      const currentFocus = focusedUser;
      // if down key is pressed multiple times on last list item, keep last item highlighted
      const fu =
        currentFocus >= users.length - 1 ? users.length - 1 : currentFocus + 1;
      setFocusedUser(fu);
    }
  };

  const handleMouseEvent = id => {
    userRef.current && userRef.current.focus();
    setScrollIntoView(false);
    setFocusedUser(parseInt(id));
  };

  const listElements = users.map((user, index) => {
    const focused = index === focusedUser;
    return (
      <User
        key={index}
        divId={index}
        data={user}
        focused={focused}
        // if it isn't focused pass null
        // the ref should be a function or a ref object or null
        ref={focused ? userRef : null}
        handleKeyPress={handleKeyPress}
        handleMouseEvent={handleMouseEvent}
      />
    );
  });

  return <div className="result-list">{listElements}</div>;
};

export default List;