【问题标题】:useImperativeHandle usage for children componenent but cannot get function from parent子组件的 useImperativeHandle 用法,但无法从父组件获取功能
【发布时间】:2021-10-27 19:36:26
【问题描述】:

我有一个由 react 编写的应用程序:

主要应用是:

function App({articles}) {
    ...
    const SortVote=()=>{
      console.log(childRef.current);
      console.log(Object.getOwnPropertyNames(childRef.current))
      childRef.current.SortVote();
    }
  
    const [art, setArt]= useState(articles);
    const childRef = useRef();

    return (
        <div className="App">
            <h8k-navbar header={title}></h8k-navbar>
            <div className="layout-row align-items-center justify-content-center my-20 navigation">
                <label className="form-hint mb-0 text-uppercase font-weight-light">Sort By</label>
                <button data-testid="most-upvoted-link" className="small" onClick={SortVote}>Most Upvoted</button>
            </div>
            <Articles articles={art} cRef={childRef}/>
        </div>
    );

}

子组件是:

function Articles({ articles, cRef }) {
  const [arts, setArts] = useState(articles);
  const sortVote = () => {
    const result = articles.sort((a, b) => {
      if (a.upvotes > b.upvotes) {
        return -1;
      }
      if (a.upvotes < b.upvotes) {
        return 1;
      }
      return 0;
    });
    setArts(result);
  };
  const sortDate = () => {
    const result = articles.sort((a, b) => {
      if (a.date > b.date) {
        return -1;
      }
      if (a.date < b.date) {
        return 1;
      }
      return 0;
    });
    setArts(result);
  };
  useImperativeHandle(cRef, () => ({
    sortVote,
    sortDate
  }));
  if (articles)
    return (
      <div className="card w-50 mx-auto">
        <table>
          <thead>
            <tr>
              <th>Title</th>
              <th>Upvotes</th>
              <th>Date</th>
            </tr>
          </thead>
          <tbody>
            {arts.map((item, index) => (
              <tr data-testid="article" key={index}>
                <td data-testid="article-title">{item.title}</td>
                <td data-testid="article-upvotes">{item.upvotes}</td>
                <td data-testid="article-date">{item.date}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    );
}

我在子组件中使用 useImperativeHandle 并尝试在父组件中使用 'childRef.current.SortVote()' 来调用子组件功能。但是浏览器有错误:

childRef.current.SortVote is not a function

完整代码在:https://stackblitz.com/edit/react-vy7df9

在useImpertiveHandle钩子中,SortVote和sortDate已经定义了函数,为什么这里还是报错SortVote is not function?

【问题讨论】:

    标签: reactjs react-hooks parent-child use-ref react-forwardref


    【解决方案1】:

    问题

    useImperativeHandle 与传递的 React refs 一起使用,不是保存 ref 值的 props。

    useImperativeHandle

    useImperativeHandle 自定义暴露的实例值 使用ref 时的父组件。与往常一样,命令式代码使用 在大多数情况下应避免使用 refs。 useImperativeHandle应该 与forwardRef一起使用:

    function FancyInput(props, ref) {
      const inputRef = useRef();
      useImperativeHandle(ref, () => ({
        focus: () => {
          inputRef.current.focus();
        }
      }));
      return <input ref={inputRef} ... />;
    }
    FancyInput = forwardRef(FancyInput);
    

    在您的代码中,您没有将 ref 传递给子组件,而是传递了一个具有 ref 值的 prop。

    <Articles cRef={childRef} articles={art} />
    

    对

    <Articles ref={childRef} articles={art} />
    

    解决方案

    首先,更新Articles 组件的函数签名以使用React ref。请注意,这是传递给函数的 第二个 参数,props 对象是第一个。

    function Articles({ articles }, ref) {
      ...
    
      useImperativeHandle(ref, () => ({
        sortVote,
        sortDate
      }));
    
      if (articles) {
        return (
          ...
        );
      }
      return null;
    }
    

    接下来,将Articles 组件包装在React.forwardRef 中。

    Articles = forwardRef(Articles);
    

    最后,将引用传递给Articles 组件。注意,是sortVote,不是SortVote。

    function App({articles}) {
      const [art, setArt]= useState(articles);
      const childRef = useRef();
    
      ...
      const SortVote=()=>{
        console.log(childRef.current);
        console.log(Object.getOwnPropertyNames(childRef.current))
        childRef.current.sortVote();
      }
    
      return (
        <div className="App">
          ...
          <Articles
            ref={childRef}
            articles={art}
          />
        </div>
      );
    }
    

    更新

    您在子 Articles 组件中也存在错误。 Array.prototype.sort 进行就地排序,这意味着它会改变 arts 状态。您首先需要在排序之前复制数组。 Array.prototype.slice 是一种简单的函数式编程方法,可以在排序之前内联复制数组。

    function Articles({ articles }, ref) {
      const [arts, setArts] = useState(articles);
    
      const sortVote = () => {
        const result = articles.slice().sort((a, b) => {
          if (a.upvotes > b.upvotes) {
            return -1;
          }
          if (a.upvotes < b.upvotes) {
            return 1;
          }
          return 0;
        });
        setArts(result);
      };
    
      const sortDate = () => {
        const result = articles.slice().sort((a, b) => {
          if (a.date > b.date) {
            return -1;
          }
          if (a.date < b.date) {
            return 1;
          }
          return 0;
        });
        setArts(result);
      };
    
      ...
    

    【讨论】:

      猜你喜欢
      • 2019-06-29
      • 2016-07-15
      • 2017-01-04
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      • 2020-04-16
      • 2019-04-07
      相关资源
      最近更新 更多