繁体   English   中英

如何使用 React Hooks 实现刷新按钮?

[英]how to implement a refresh button with React Hooks?

我正在尝试实现刷新按钮,但无法完成。

这是我的代码的样子:

// ParentComponent.js
const ParentComponent = () => {
  const { loading, error, data } = useItems();

  return (
    <ChildComponent items={data} />
  );

  ... rest of my code that shows the data
};

// ChildComponent.js
const ChildComponent = ({ items }) => { 
  return (
    // Logic that renders the items in <li>s
    <button onClick={() => console.log('Clicking this button should refresh parent component')}
  )
};

// services/useItems.js
const useItems = () => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  useEffect(() => {
    axios
      .get(API_URL + '/counter')
      .then((response) => {
        setItems(response.data);
        setLoading(false);
      })
      .catch((error) => {
        setLoading(false);
        setError(error.message);
      });
    }, []);

    return { loading, error, data: counters };

}

我尝试了几种方法,但都没有奏效。 任何帮助将不胜感激:)

我不认为useEffect是这里的正确机制。 由于它是一个命令式调用,没有任何反应, useState可以很好地完成工作:

// ParentComponent.js
const ParentComponent = () => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  const refresh = () => {
    axios.get(API_URL + '/counter').then((response) => {
      setItems(response.data);
      setLoading(false);
    }).catch((error) => {
      setLoading(false);
      setError(error.message);
    });
  };
  useEffect(refresh, []);

  return (
    <ChildComponent items={items} refresh={refresh} />
  );

  // ... rest of my code that shows the data
};

// ChildComponent.js
const ChildComponent = ({ items, refresh }) => { 
  return (
    // Logic that renders the items in <li>s
    <button onClick={refresh}>
      Refresh
    </button>
  )
};

有几个小部件需要您进行更改以解决问题。

  1. 您需要创建一个用于refresh的通信
    • 创建一个函数来处理任何刷新处理。
    • 将此作为道具传递给子组件
    • 在子组件中,在必要的事件上调用它,在这种情况下click
  2. 现在,由于您正在使用钩子,您需要调用它。
    • 您可以在useItem挂钩中添加一个函数refreshData并公开它
    • 单击按钮时调用此函数。
    • 您还必须在钩子中添加一个标志并更新要在其更改时触发的useEffect
    • 此函数是必需的,因为setItems仅在钩子内部可用。

以下是一个工作示例:

 const { useState, useEffect } = React; // ParentComponent.js const ParentComponent = () => { const { loading, error, data, refreshData } = useItems(); const refreshFn = () => { refreshData() } return ( <ChildComponent items={data} onClick={refreshFn}/> ); // ... rest of my code that shows the data }; // ChildComponent.js const ChildComponent = ({ items, onClick }) => { const onClickFn = () => { console.log('Clicking this button should refresh parent component') if(!!onClick) { onClick(); } } return ( // Logic that renders the items in <li>s <div> <button onClick={ () => onClickFn() } >Refresh</button> <ul> { items.map((item) => <li key={item}>{item}</li>) } </ul> </div> ) }; // services/useItems.js const useItems = () => { const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [refresh, setRefresh] = useState(false) useEffect(() => { if (refresh) { setItems(Array.from({ length: 5 }, () => Math.random())); setRefresh(false) } }, [ refresh ]); return { loading, error, data: items, refreshData: () => setRefresh(true) }; } ReactDOM.render(<ParentComponent/>, document.querySelector('.content'))
 <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div class='content'></div>


正如hackape正确评论的那样,我们需要添加refresh检查并仅在其为true时才获取数据

一个非常简单的技巧是增加一个整数状态,我们称之为version ,这将触发<ParentComponent />的重新渲染,如果useEffect依赖于version ,它将重新执行回调,所以你得到“刷新”效果。

// ParentComponent.js
const ParentComponent = () => {
  const [version, setVersion] = useState(0)
  // when called, add 1 to "version"
  const refresh = useCallback(() => {
    setVersion(s => s + 1)
  }, [])

  const { loading, error, data } = useItems(version);

  return (
    <ChildComponent items={data} refresh={refresh} />
  );
};

// ChildComponent.js
const ChildComponent = ({ items, refresh }) => { 
  return (
    // Logic that renders the items in <li>s
    <button onClick={refresh} />
  )
};

// services/useItems.js
const useItems = (version) => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  useEffect(() => {
    axios
      .get(API_URL + '/counter')
      .then((response) => {
        setItems(response.data);
        setLoading(false);
      })
      .catch((error) => {
        setLoading(false);
        setError(error.message);
      });
    }, [version]);  // <-- depend on "version"

    return { loading, error, data: counters };

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM