Loading...
(function(){<br />
let canvas = document.createElement('canvas'),<br />
ctx = canvas.getContext('2d'),<br />
w = canvas.width = innerWidth,<br />
h = canvas.height = innerHeight,<br />
particles = [],<br />
properties = {<br />
bgColor : 'rgba(17, 17, 19, 1)',<br />
particleColor : 'rgba(255, 40, 40, 1)',<br />
particleRadius : 3,<br />
particleCount : 60,<br />
particleMaxVelocity : 0.5,<br />
lineLength : 150,<br />
particleLife : 6,<br />
};<br />
<br />
document.querySelector('body').appendChild(canvas);<br />
<br />
window.onresize = function() {<br />
w = canvas.width = innerWidth;<br />
h = canvas.height = innerHeight;<br />
}<br />
<br />
class Particle {<br />
constructor() {<br />
this.x = Math.random()*w;<br />Loading...
K Query is a tool included in Redux Toolkit. When using it, there is no need to create separate state, actions, or dispatches to fetch data from a server. RTK Query handles this automatically. It caches data and only makes requests to the server when the data has changed.
All examples in this article are based on a React application. I do not cover all of RTK Query's capabilities, so for a deeper understanding, be sure to check out the official documentation.
The names of some methods may change as Redux Toolkit is updated.
Documentation:
https://redux-toolkit.js.org/rtk-query/overview
Installing Redux Toolkit in the project:
npm install @reduxjs/toolkit
To create the Provider and pass the store in index.js, I use React Redux:
npm install react-redux
This is the standard approach commonly used in projects that use Redux.
1import React from 'react';2import * as ReactDOMClient from "react-dom/client";3import { Provider } from "react-redux";4import './index.scss';5import ErrorBoundry from './components/error-boundry';6import App from './App';78const store = setupStore();910const container = document.getElementById("root");11const root = ReactDOMClient.createRoot(container);1213root.render(14 <Provider store={store}>15 <ErrorBoundry>16 <App />17 </ErrorBoundry>18 </Provider>19);20
Create a file where your RTK Query functions will be defined, for example cards.js.
Import the following:
1import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/dist/query/react";
Then create the API:
1const api_uri = process.env.REACT_APP_API;23export const cardsAPI = createApi({4 reducerPath: 'cardsAPI',5 baseQuery: fetchBaseQuery({baseUrl: api_uri}),6 tagTypes: ['Cards'],7 endpoints: (build) => ({8910 })11})12
Use build.query() to create GET requests.
Documentation:
https://redux-toolkit.js.org/rtk-query/usage/queries
1export const cardsAPI = createApi({2 reducerPath: 'cardsAPI',3 baseQuery: fetchBaseQuery({baseUrl: api_uri}),4 tagTypes: ['Cards'],5 endpoints: (build) => ({6 fetchAllCards: build.query({7 query: ({limit = 10, orderBy = '0', skip = 0} ) => ({8 url: `/cards`,9 params: {10 skip: skip,11 limit: limit,12 order_by: orderBy13 }14 }),15 providesTags: result => ['Cards']16 }),17 fetchCard: build.query({18 query: ({id = 0} ) => ({19 url: `/cards/${id}`,20 }),21 providesTags: result => ['Cards']22 }),23 })24})
For requests that modify data or should not be executed automatically when a page loads, use build.mutation().
Documentation:
https://redux-toolkit.js.org/rtk-query/usage/mutations
1 editCard: build.mutation({2 query: ({body, id}) => ({3 url: `/cards/${id}`,4 method: 'PATCH',5 body6 }),7 providesTags: result => ['Cards']8 }),
RTK Query provides transformResponse and transformErrorResponse for processing responses before they reach your components.
1 fetchPosts: build.query({2 query: ({limit = 10, skip = 0}) => ({3 url: `/posts`,4 params: {5 skip: skip,6 limit: limit7 }8 }),9 providesTags: result => ['Post'],10 transformResponse: (response, meta, arg) => response.posts,11 }),12
Used in query requests. The specified tag is attached to the cached data returned by the query.
A simple example:
providesTags: ['Posts']
These tags are later used by mutations to refresh cached data.
Used only in mutation requests.
Specify the same tags used in providesTags for the data that should be refreshed.
A simple example:
invalidatesTags: ['Posts']
After creating the API, configure your Redux store.
Import combineReducers, configureStore, and the API you created:
1import {combineReducers, configureStore} from "@reduxjs/toolkit";2import {cardsAPI} from "../services/cardsAPI.js";
Create a rootReducer and setupStore function:
1const rootReducer = combineReducers({2 // Regular Redux reducers can also be added here3 [cardsAPI.reducerPath]: cardsAPI.reducer,4})56export const setupStore = () => {7 return configureStore({8 reducer: rootReducer,9 middleware: (getDefaultMiddleware) =>10 getDefaultMiddleware()11 .concat(cardsAPI.middleware)12 })13}
In a component, you can access:
If we used the build.query() method when creating a request, the query hook will be named according to the following pattern:
use + our query name with the first letter capitalized + Query
In this case, we destructure the returned object and extract the required data from it.
The request is executed when the component is created. You can pass arguments and options to it. In the case of the API we have written, arguments are passed as follows:
1const {data: cards,2 error: errorCards,3 isLoading: isCardsLoading,4 isSuccess: isCardsSuccess,5 } = CardsAPI.useFetchAllCardsQuery();67 const {data,8 error,9 isLoading,10 isSuccess,11 } = CardsAPI.useFetchAllOptionsQuery({limit: OptionsLimit}, {skip: OptionsSkip});
In the options, we can transform the query result:
1const {card,2 error,3 isLoading,4 } = projectAPI.useFetchCardQuery({id: cardId}, {5 selectFromResult: ({ data, error, isLoading}) => {6 // Various transformations can be applied here7 return ({8 card: data?.card[0],9 error: error,10 isLoading: isLoading11 })12 },13 skip14 });
If we used the build.mutation() method when creating a request, the mutation hook will be named according to the following pattern:
use + our mutation name with the first letter capitalized + Mutation
In the case of a mutation, we destructure the returned array, which contains the mutation function (named after the request) and an object with the request data.
1const [editCard,2 {error,3 isError,4 isLoading,5 isSuccess,6 reset}] = CardsAPI.useEditCardMutation();
I used the reset function, for example, to reset the submission state after closing a modal window and remove all messages. Otherwise, the successful submission status remains true if it is not reset.
The mutation function can be used like a regular function by passing the required data for the request.
For example, if we changed the card title, we can send the request when submitting the form:
1const onEditCard = (e) => {2 e.preventDefault();3 if(name) {4 const body = {5 "name": name6 }78 editCard({body});9 }10 }
To avoid wrapping the object in a new object, we can use the .unwrap() method.
1 editCard(body).unwrap();
We also use .unwrap() when we need to specify .then().
1confirm(data)2.unwrap()3.then(() => {4 setShow(false);5});
I created a separate variable for the skip option, which we pass to the query. By default, I set its value to true.
1const [skip, setSkip] = useState(true);2const {data} = PosttAPI.useFetchPostQuery({postId}, {skip});
In useEffect, I monitor the id required to fetch post data. If the id exists, I change skip to false, and the request is triggered.
1useEffect(() => {2 if(postId) {3 setSkip(false)4 }5}, [postId])
In my case, I converted the file to an object URL inside the query function.
1getFile: build.mutation({2 query: ({id}) => ({3 url: `/file`,4 method: 'GET',5 params: {67 id: id,8 },9 responseHandler: async (response) => window.URL.createObjectURL(await response.blob()),10 cache: "no-cache",11 }),12 providesTags: result => ['File'],13 }),14
On the component page, create a link and set the href attribute to the value of the URL received above. In the download attribute, specify the name of the file that should be downloaded. Add the link to the body and create a click event on the link.
1const [getFile, {}] = siteAPI.useGetFileMutation();23 const getFile = async () => {4 if(id) {5 const url = await getFile({id});6 const link = document.createElement('a');7 link.setAttribute('href', url?.data);8 link.setAttribute(9 'download',10 `fileName.html`,11 );1213 // Append to html link element page14 document.body.appendChild(link);1516 // Start download17 link.click();1819 // Clean up and remove the link20 link.parentNode.removeChild(link);21 }22 }
I have described only a small part of the capabilities of RTK Query, so explore the documentation and use it! :)