开源日报每天推荐一个 GitHub 优质开源项目和一篇精选英文科技或编程文章原文,坚持阅读《开源日报》,保持每日学习的好习惯。
2024年1月5日,开源日报第1065期:
今日推荐开源项目:《netron》
今日推荐英文原文:《React Query is the best thing that happened to React》


开源项目

今日推荐开源项目:《netron》传送门:项目链接

推荐理由:神经网络、深度学习和机器学习模型的可视化工具, PyTorch, TorchScript, TensorFlow, OpenVINO, RKNN, MediaPipe, ML.NET 和 scikit-learn

网站直达:netron.app


英文原文

今日推荐英文原文:React Query is the best thing that happened to React

推荐理由:React Query是React中的一项强大数据获取库,被描述为在React开发中的一次重大变革。它简化了数据管理,优化了网络请求,并增强了缓存策略。文章认为从Redux转向React Query是值得的,特别是在处理API层数据方面,React Query已经能够很好地胜任


React Query is the best thing that happened to React

Background

React Query is a powerful data-fetching library, has emerged as a game-changer in React development. It simplifies data management, optimizing network requests, and enhancing caching strategies.

Link to the package — https://www.npmjs.com/package/@tanstack/react-query

img

Is it worth shifting from Redux to react-query??? Lets find out!!!

How does it make a difference?

  1. Effortless Data Fetching:
  • Without React Query: Manually handling async calls with fetch or axios.
  • With React Query: Use useQuery for auto-fetching, reducing code complexity.
// Without React Query
fetch('/api/data').then(response => response.json()).then(data => ...);

// With React Query
const { data } = useQuery('data', () => fetch('/api/data')
                      .then(response => response.json())
                  );

2. Automatic Caching:

  • Without React Query: Implement custom caching mechanisms.
  • With React Query: Caching is built-in and updates automatically.
// Without React Query
const cachedData = localStorage.getItem('cachedData');

// With React Query
const { data } = useQuery(['items'], fetchData, { enabled: isConnected });

3. Real-time Updates:

  • Without React Query: Complex setup using Web Sockets and manual state management.
  • With React Query: Seamless integration of real-time features.
// Without React Query
socket.on('dataUpdate', updatedData => ...);

// With React Query
const { data } = useQuery('data', fetchData);

4. Global State Management:

  • Without React Query: Combine Context or other state management libraries.
  • With React Query: Use hooks for data and global state.
// Without React Query
const { data, dispatch } = useContext(AppContext);

// With React Query
const { data, mutate } = useQuery(['items'], fetchData);

5. Network Request Optimization:

  • Without React Query: Manually manage network requests and debounce.
  • With React Query: Automatic query optimization
// Without React Query
const debouncedFetch = debounce(fetchData, 300);

// With React Query
const { data } = useQuery(['items'], fetchData, { 
                                 refetchOnWindowFocus: false 
                                 }
                  );

6. Server Pagination & Infinite Loading:

  • Without React Query: Handle pagination manually with complex logic.
  • With React Query: Streamlined infinite loading and pagination.
// Without React Query
const loadMore = () => fetchMoreData(pageNumber);

// With React Query
const { data, fetchNextPage } = useInfiniteQuery(['items'], fetchPageData);

7. Error Handling & Retrying:

  • Without React Query: Implement error handling and retry logic manually.
  • With React Query: Built-in error handling and retrying.
// Without React Query
fetch('/api/data').catch(error => retry(fetchData, 3, error));

// With React Query
const { data } = useQuery(['items'], fetchData, { retry: 3 });

8. Developer-Friendly DevTools:

  • Without React Query: Rely on browser developer tools for insights.
  • With React Query: Debug with dedicated React Query DevTools.

To see in action, here is an example of implementing displaying of data with pagination using react query.

Example:

Let's assume you have a set of data with pagination and filters. On clicking tabs you change filter, you have a dropdown to select nunber of items to display, you have previous and next buttons.

Implementing this using react-query:

const Component = () => {

  const [filterA, setFilterA] = React.useState<boolean>(false);
  const [page, setPage] = React.useState<number>(1);
  const [pageSize, setPageSize] = React.useState<number>(10);

  const GetData= async (filters) => {
   try {
    const filterString = filters
     ? "?" + filters.map((filter) => filter.key + "=" + filter.value).join("&")
     : "";
      const url = "/api/data/" + filterString;
      const res = await axios.get(url);
      return res.data;
    } catch (err) {
      throw err;
    }
  };

  const {
    data,
    status,
    error
  } = useQuery(["data", filterA, page, pageSize], () =>
    GetData([
      {
        key: "filter_a",
        value: filterA,
      },
      {
        key: "page",
        value: page,
      },
      {
        key: "page_size",
        value: pageSize,
      },
    ])
  );

  return (
          <Tabs>
            <TabList>
              <Tab
                onClick={() => {
                  setFilterA(false);
                  setPage(1);
                }}
              >
                Tab 1
              </Tab>
              <Tab
                onClick={() => {
                  setFilterA(true);
                  setPage(1);
                }}
              >
                Tab 2
              </Tab>
              <Flex>
                <Button
                  onClick={() => setPage(page - 1)}
                  disabled={page === 1}
                >
                  Previous
                </Button>
                <Text>
                  {page}
                </Text>
                <Button
                  onClick={() => setPage(page + 1)}
                  disabled={data?.next === null}
                >
                  Next
                </Button>
                <Select
                  value={pageSize}
                  onChange={(e) => setPageSize(Number(e.target.value))}
                >
                  <option value={10}>10</option>
                  <option value={20}>20</option>
                  <option value={50}>50</option>
                </Select>
              </Flex>
            </TabList>

            <TabPanels>
              <TabPanel>
                {status === "loading" ? (
                  <ComponentLoader />
                ) : (
                  <DataTable data={data.results} />
                )}
              </TabPanel>
              <TabPanel>
                {status === "loading" ? (
                  <ComponentLoader />
                ) : (
                  <DataTable data={data.results} />
                )}
              </TabPanel>
            </TabPanels>
          </Tabs>
  );
};

export default Component;

Note:

Like useEffect has dependencies array, u can treat the array in useQuery similarly, whenever any variable changes in the array, the API gets triggered again. The same info will be used to cache the data and remember the corresponding API for it.

useQuery(["data", a, b, c], () => GetData(a,b,c))

So here whenever the a, b, c variable changes it gets triggered again.

Conclusion:

Yes, it’s definitely worth it to shift from Redux to react-query. You would still need Redux if u want to communicate complex local data across the components.

Such use case when you would need Redux:

When u have multiple components, and you are toggling display of components on different button clicks in different components which doesn’t have same parents.

But you no longer need to store the API layer data using Redux, since everything gets handled by react-query.

A round of applause, dear readers, for reaching the end — if you enjoyed this article as much as a developer loves a well-commented code, give it a clap to brighten my day! 👏


下载开源日报APP:https://openingsource.org/2579/
加入我们:https://openingsource.org/about/join/
关注我们:https://openingsource.org/about/love/