開源日報每天推薦一個 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/