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

时间:2020-10-12 03:30:21

标签: javascript reactjs 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 };

}

我尝试了几种方法,但没有一项工作。任何帮助将不胜感激:)

3 个答案:

答案 0 :(得分:2)

我不认为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 :(得分:1)

您需要进行一些更改以解决问题。

  1. 您需要为refresh创建通信
    • 创建一个函数来处理任何刷新处理。
    • 将此作为道具传递给子组件
    • 在子组件中,必要时调用它,在这种情况下为click
  2. 现在,由于您正在使用钩子,因此需要将其调用。
    • 您可以在refreshData钩子中添加函数useItem并将其公开
    • 单击按钮即可调用此功能。
    • 您还必须在钩子中添加一个标志并更新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时获取数据

答案 2 :(得分:1)

一个非常简单的技巧是增加整数状态,我们将其称为version,这将触发<ParentComponent />的重新渲染,并且如果useEffect依赖于{{1} },它将重新执行回调,因此您将获得“刷新”效果。

version