A react library for easily managing typed url query parameters.
Installations
npm install react-nav-query-params
Developer Guide
Typescript
Yes
Module System
CommonJS
Node Version
20.10.0
NPM Version
6.14.18
Score
71.5
Supply Chain
93
Quality
78.7
Maintenance
100
Vulnerability
100
License
Releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (93.38%)
CSS (4.12%)
HTML (1.76%)
JavaScript (0.74%)
Developer
Download Statistics
Total Downloads
1,253
Last Day
1
Last Week
18
Last Month
37
Last Year
519
GitHub Statistics
61 Commits
1 Watching
2 Branches
1 Contributors
Bundle Size
19.01 kB
Minified
5.33 kB
Minified + Gzipped
Package Meta Information
Latest Version
0.1.1
Package Id
react-nav-query-params@0.1.1
Unpacked Size
252.10 kB
Size
39.38 kB
File Count
7
NPM Version
6.14.18
Node Version
20.10.0
Publised On
04 Oct 2024
Total Downloads
Cumulative downloads
Total Downloads
1,253
Last day
0%
1
Compared to previous day
Last week
200%
18
Compared to previous week
Last month
-7.5%
37
Compared to previous month
Last year
-29.3%
519
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
react-nav-query-params
A react package for easily managing query parameters across various routes throughout an application with typescript support, serialization/deserialization, and error handling. Note: This package is still in development, so there may be some bugs and major changes over time.
Install
1npm install --save react-nav-query-params
Guide
Note: This package is meant for mainly TypeScript users as it works best in TypeScript-based applications to type URL query parameters and group them based on routes. JavaScript users can still benefit from using this package, but they will not get all the advantages that the package has to offer.
Defining the Routes and Param Keys
TypeScript(TS) Users
1 2// Import the function from the package 3import { createNavManager } from "react-nav-query-params"; 4 5// (Suggested) Create a variable to store your route key strings 6export const Routes = { 7 Route1: "route1", 8 Route2: "route2", 9 Route3: "route3", 10}; 11 12// (Optional) Define the types of query params that are used in the application grouped by route keys used above 13// keys are strings corresponding to different pages or components (route key) 14// values correspond to the name and type of the query params associated with the route key (ignore if not using TypeScript (JavaScript users)) 15 16type SampleStringUnion = "one" | "two" | "three"; 17 18enum SampleEnum = { 19 one = "one", 20 two = "two", 21 three = "three" 22} 23 24export type QueryParamTypeMapping { // <-- * use type 25 [Routes.Route1]: { 26 param1: {[sample in SampleStringUnion]?: boolean}; 27 param2: SampleStringUnion; 28 param3: number[]; 29 param4: string; 30 }, 31 [Routes.Route2]: { 32 param5: boolean; 33 param6: number; 34 }, 35 [Routes.Route3]: { 36 param7: "first" | "second" | "third"; 37 param8: string; 38 param9: SampleEnum; 39 } 40} 41 42 43// * there are limited types you can use with this package that are grouped into one 44// * of two categories based on how encoding/decoding is handled 45// * simple types (SimpleType) => string | number | boolean | bigint 46// * complex types => Record<string, SimpleType> | Date | Array<SimpleType> 47// * encoding/decoding is done based on type key (a key associated with a specific type) 48// The supported type keys are listed below under the section 'List of Type Keys & Types' 49 50const { creator, activator } = createNavManager({ 51 customTypeKeyMapping: {} 52}); 53 54// use the activator function returned to help enforce typescript's type checking/auto-completion 55// activator function helps to determine the corresponding type key used for encoding/decoding given the type of each params keys 56// (could also exclude the generic argument, as seen in the JS example below) 57 58const routeMapping = activator<QueryParamTypeMapping>({ 59 [Routes.Route1]: { 60 typeKeyMapping: { 61 param1: "booleanRecord", // <-- param key : type key (mapping) 62 param2: "string", 63 param3: "numberArray", 64 param4: "string", 65 }, 66 programmaticNavigate: false, // for reading query params (optional) 67 }, 68 [Routes.Route2]: { 69 typeKeyMapping: { 70 param5: "boolean", 71 param6: "number", 72 }, 73 }, 74 [Routes.Route3]: { 75 typeKeyMapping: { 76 param7: "string", 77 param8: "string", 78 param9: "stringEnum", 79 }, 80 options: { // here you can specify extra options for the 81 // param key based on the type key that is used 82 param9: { // param9 is a 'stringEnum' which has an option of enumType 83 // to specify the valid values when encoding/decoding 84 enumType: Object.values(SampleEnum), 85 }, 86 } 87 }, 88}); 89 90 91// call creator function with the routeMapping 92// and you will get back a context to wrap around the application 93// as well as a hook to manage the query params given a specific route key 94// (Refer to the 'Usage' section below) 95 96export const { NavQueryContext, useNavQueryParams } = creator( 97 routeMapping 98); 99
JavaScript(JS) Users
1 2// Import the function from the package 3import { createNavManager } from "react-nav-query-params"; 4 5// (Suggested) Create a variable to store your route strings 6export const Routes = { 7 Route1: "route1", 8 Route2: "route2", 9 Route3: "route3", 10}; 11 12// * there are limited types you can use with this package that are grouped into one 13// * of two categories based on how encoding/decoding is handled 14// * simple types (SimpleType) => string | number | boolean | bigint 15// * complex types => Record<string, SimpleType> | Date | Array<SimpleType> 16// * encoding/decoding is done based on type key (a key associated with a specific type) 17// The supported type keys are listed below under the section 'List of Type Keys & Types' 18 19const { creator, activator } = createNavManager({ 20 customTypeKeyMapping: {} 21}); 22 23 24const routeMapping = activator({ 25 [Routes.Route1]: { 26 typeKeyMapping: { 27 param1: "booleanRecord", // <-- param key : type key (mapping) 28 param2: "string", 29 param3: "numberArray", 30 param4: "string", 31 }, 32 programmaticNavigate: false, // for reading query params (optional) 33 }, 34 [Routes.Route2]: { 35 typeKeyMapping: { 36 param5: "boolean", 37 param6: "number", 38 }, 39 }, 40 [Routes.Route3]: { 41 typeKeyMapping: { 42 param7: "string", 43 param8: "string", 44 param9: "stringEnum", 45 }, 46 options: { // here you can specify extra options for the 47 // param key based on the type key that is used 48 param9: { // param9 is a 'stringEnum' which has an option of enumType 49 // to specify the valid values when encoding/decoding 50 enumType: ["one", "two", "three"], 51 }, 52 } 53 }, 54}); 55 56 57// call creator function with the routeMapping 58// and you will get back a context to wrap around the application 59// as well as a hook to manage the query params given a specific route key 60// (Refer to the 'Usage' section below) 61 62export const { NavQueryContext, useNavQueryParams } = creator( 63 routeMapping 64); 65
Setup(Both TS/JS Users)
1 2// (example below uses react-router v6, and will look slightly different for other routing solutions) 3// (This example is much more complicated because of how react-router v6 defines routes 4// and how it prevents access to the location and history object from the components that are not used inside the main Browser router object) 5// (For other routing solutions, such as Next.js router the setup may be easier) 6// The main purpose of this step is to provide the package access to the location and history objects 7// used by your routing solution so that the package can read and update the query params 8 9 10// If you are using react-router v6, add a component 'RouteBasePage' to the root of your router with the path '/' 11// that uses the 'NavQueryContext' given by this package (look below for the implementation of RouteBasePage) 12const router = createBrowserRouter([ // from react-router v6 13 { 14 path: "/", 15 element: <RouteBasePage />, 16 children: [{ 17 path: "/", 18 element: <ReadingParams />, 19 index: true, 20 }, 21 { 22 path: "/route1", 23 element: <NavigatingAndSettingParams /> 24 }] 25 } 26]) 27 28// In the root App component... 29function App(){ 30 return ( 31 <div className="App"> 32 <RouterProvider router={router} /> {/* from react-router v6 */} 33 </div> 34 ); 35} 36 37 38 39// In a child component of the app component need to create an adapter object that tells this package how to manage history and location objects. 40// need access to the history.push/replace and location data from the react-router v6 41 42import { Adapter } from "react-nav-query-params"; //<-- TS users only 43import { useLocation, useNavigate, Outlet } from "react-router-dom"; //<-- react router v6 users only 44 45function RouteBasePage(){ 46 // The following is specific to react-router v6 and might look different for each routing solution, 47 // but the adapter created needs to be provided in a similar manner in the NavQueryContext.Provider 48 // or else the useNavQueryParams hook will not work 49 50 const location = useLocation(); // <-- for react-router, can only be called in a child component of RouterProvider 51 const navigate = useNavigate(); // <-- for react-router, can only be called in a child component of RouterProvider 52 53 const adapter = useMemo(() => { //<-- JS users, const adapter = useMemo<Adapter>(() => { //<-- TS users 54 return { 55 location: location, 56 pushLocation: (l) => { // the type of 'l' here is Adapter["location"] for TS users 57 if (l.search !== null || l.search !== undefined) 58 navigate("?" + l.search, { replace: false }); 59 }, 60 replaceLocation: (l) => { 61 if (l.search !== null || l.search !== undefined) 62 navigate("?" + l.search, { replace: true }); 63 }, 64 }; 65 }, [location, navigate]); 66 67 return ( 68 <NavQueryContext.Provider 69 value={{ 70 adapter: adapter, 71 }} 72 > 73 <Outlet /> 74 </NavQueryContext.Provider> 75 ); 76} 77
Usage(Both TS/JS Users)
1 2// A component where you read the query params 3function ReadingParams(){ 4 const { getQueryParams: getQueryParamsRoute1, clearQueryParams: clearQueryParamsRoute1 } = useNavQueryParams(Routes.Route1); 5 6 // All functions returned by the hook are memoized using useCallback, 7 // getQueryParams has a dependency on the query string used in the URL 8 // so if the query string changes, all dependency arrays with the 9 // function as a dependency will rerun 10 11 // url: localhost:3000/route1?param1=%7B%22one%22%3Atrue%7D¶m2=three 12 13 const queryParams = useMemo(() => { 14 return getQueryParamsRoute1(); 15 },[getQueryParamsRoute1]) 16 17 console.log( 18 "Value of param2 query param is 'two': ", 19 queryParams.values?.param2 === "two") //<-- false 20 21 // getQueryParamsRoute1 function will get the query params that 22 // are associated with the 'route1' route key which is mapped to the 23 // the url path route1 24 25 26 27 28 return ( 29 <div> 30 {/* The below button is optional */} 31 <button 32 // clearQueryParamsRoute1 clears all query params from 33 // url associated with route1 34 onClick={() => { clearQueryParamsRoute1() }} 35 > 36 Clear Params 37 </button> 38 Check the console to see the query params 39 </div> 40 ) 41} 42 43// In some other component... 44function NavigatingAndSettingParams() { 45 const { getQueryString } = useNavQueryParams(Routes.Route1); 46 47 const queryString = getQueryString({ param2: "three", param1: { "three": true }, param3: [10, 30] }, 48 { // (optional argument) 49 replaceAllParams: true, // replace the current query params, when getting the query string 50 full: true, // include the '?' in the query string 51 }); 52 53 54 const navigate = useNavigate(); // from react router v6 55 56 // url: localhost:3000/route1?param2=three¶m1=%7B%three%22%3Atrue%7D& 57 // param3=10%2C30 58 59 60 return ( 61 <div> 62 <button onClick={() => navigate("/route1" + queryString)}>Click Me</button> 63 </div> 64 ); 65} 66
List of Provided Type Keys & Types & Options
1// (It is possible to create your own type keys / types as well as options) 2// (Look below at the Custom Types / Type Keys section) 3type TypeKeys = { 4 // simple types 5 "string": string; 6 "number": number; 7 "boolean": boolean; 8 9 // complex types 10 // array types 11 "stringArray": string[]; 12 "numberArray": number[]; 13 "booleanArray": boolean[]; 14 // record types 15 "stringRecord": Record<string, string>; 16 "numberRecord": Record<string, number>; 17 "booleanRecord": Record<string, boolean>; 18 // enums 19 "stringEnum": string; 20 "numberEnum": number; 21 // date 22 "date": Date; 23}; 24 25type TypeKeyToOptions = { 26 // array types 27 stringArray: { 28 separator: string; // specify the separator used when encoding/decoding 29 // the array i.e. '*' rather than ','(%2C) 30 expanded?: boolean; // set to true to encode in the long form (i.e. param3=20¶m3=40) 31 // rather than short form (param3=20,40) 32 }; 33 numberArray: { 34 separator: string; 35 expanded?: boolean; 36 }; 37 booleanArray: { 38 separator: string; 39 expanded?: boolean; 40 }; 41 // record types 42 stringRecord: { 43 objectStartSeparator?: string; // replaces the objectStartSeparator character'{' when 44 // encoding/decoding 45 objectEndSeparator?: string; 46 objectEntrySeparator?: string; 47 keyValueSeparator?: string; 48 }; 49 numberRecord: { 50 objectStartSeparator?: string; 51 objectEndSeparator?: string; 52 objectEntrySeparator?: string; 53 keyValueSeparator?: string; 54 }; 55 booleanRecord: { 56 objectStartSeparator?: string; 57 objectEndSeparator?: string; 58 objectEntrySeparator?: string; 59 keyValueSeparator?: string; 60 }; 61 stringEnum: { 62 enumType: string[]; // specify the allowed values used when encoding/decoding the enum 63 // i.e. Object.values(EnumType) where all the values have 64 // to extends the string type 65 }; 66 numberEnum: { 67 enumType: number[]; 68 }; 69 // date 70 date: { 71 format?: "ISO", // specify the format (currently the only supported format is ISO) 72 hyphenSeperator: string; // replaces the hyphenSeperator character'-' when 73 // encoding/decoding the ISO date 74 colonSeperator: string; 75 }; 76}; 77
Custom Types / Type Keys
TypeScript(TS) Users
1 2 3function isNumericRange(value: unknown): value is [number, number] { 4 return Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number"; 5} 6 7 8const { creator, activator } = createNavManager<{ 9 numericRange: [number, number]; // <-- name: type of custom type key 10},{ 11 numericRange: { expanded?: boolean, test: string }, // <-- name: options (must extend object type) of custom typekey 12}> 13({ 14 customTypeKeyMapping: { // <- define custom type keys to encode and decode 15 numericRange: { 16 category: "custom", // <- always use "custom" 17 defaultValue: [0, 1] // <-- optional default value(used for type setting) 18 encodingMap: { // <- specify a way to encode/decode type associated with the custom type key 19 encode: (value, options) => { // <-- encode funtion takes in a value matching the type ([number, number]) and must return a string or string[] 20 return JSON.stringify(value); 21 }, 22 decode: (value, options) => { // <-- decode funtion takes in a string or string[] and 23 // must return a value matching the type ([number, number]) 24 // <- You can also throw an Error inside the decode function saying the string 25 // value cannot be decoded 26 let valueToDecode = ""; 27 if (Array.IsArray(value)){ 28 // value here is string[],(i.e. param3=20%2C3¶m3=40%2C5 => 29 // ['[20,3]','[40,5]']) so get the first entry (or use all the entries if you prefer 30 // by checking the expanded property from the options object) 31 valueToDecode = value[0]; 32 } 33 const decoded = JSON.parse(valueToDecode); 34 if (!isNumericRange(decoded)) throw new Error("Error while decoding"); 35 return decoded; // <-- [20, 3] 36 }, 37 encodingOptions: { // <- optionally specify default options for encoding/decoding 38 expanded: true, 39 test: "test", 40 }, 41 }, 42 match: (value, options) => { // <- optianally specify a way to match for the type key given an unknown value (for error handling) 43 // the options here are the defaults specified in the encodingOptions above not the options passed to the param key 44 return isNumericRange(value); 45 }, 46 }, 47 } 48}); 49 50creator() / activator() //<-- now have access to custom type/type key 51
JavaScript(JS) Users
1
2// Creating custom type keys with this package using only JavaScript is very difficult because
3// javascript does not allow you to specify types (niether does it enforce type checking)
4// and any custom type key you create with have the associated type of any, but you can still use
5// the package to create type keys that enforce/validate the query params
6
7function isNumericRange(value) {
8 return Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number";
9}
10
11
12const { creator, activator } = createNavManager({
13 customTypeKeyMapping: { // <- define custom type keys to encode and decode
14 numericRange: {
15 category: "custom", // <- always use "custom"
16 defaultValue: [0, 1], // <-- optional default value(used for type setting)
17 encodingMap: { // <- specify a way to encode/decode type associated with the custom type key
18 encode: (value, options) => { // <-- encode funtion takes in a value matching the type (any) and must return a string or string[]
19 return JSON.stringify(value);
20 },
21 decode: (value, options) => { // <-- decode funtion takes in a string or string[] and
22 // must return a value matching the type (any)
23 // <- You can also throw an Error inside the decode function saying the string
24 // value cannot be decoded
25 let valueToDecode = "";
26 if (Array.IsArray(value)){
27 // value here is string[],(i.e. param3=20%2C3¶m3=40%2C5 =>
28 // ['[20,3]','[40,5]']) so get the first entry (or use all the entries if you prefer
29 // by checking the expanded property from the options object)
30 valueToDecode = value[0];
31 }
32 const decoded = JSON.parse(valueToDecode);
33 if (!isNumericRange(decoded)) throw new Error("Error while decoding");
34 return decoded; // <-- [20, 3]
35 },
36 encodingOptions: { // <- optionally specify default options for encoding/decoding
37 expanded: true,
38 test: "test",
39 },
40 },
41 match: (value, options) => { // <- optianally specify a way to match for the type key given an unknown value (for error handling)
42 // the options here are the defaults specified in the encodingOptions above not the options passed to the param key
43 return isNumericRange(value);
44 },
45 },
46 }
47});
48
49creator() / activator() //<-- now have access to custom type/type key
50
Functions returned by useNavQueryParams(routeKey)
- getQueryString(newParams, options?)
- Args
- newParams: Object containing the new values for each param key of the associated route key, a value of null will remove an existing param if it present in the current url query string
- e.g. { param3: [12] } <- param3 will be set to param3=12 in the query string
- options: Object containing one of the following options
- full: (optional boolean) Specify whether to include the '?' in the query string
- replaceAllParams: (optional boolean) Specify whether to replace all current query params
- keyOrder: (optional object) Specify the order in which the query params associated with the route key will appear in the query string
- e.g. { param1: 4, param2: 2 } <- param2 will appear before param1 in the string as it has a lower order number
- newParams: Object containing the new values for each param key of the associated route key, a value of null will remove an existing param if it present in the current url query string
- Returns: the query string
- Args
- getQueryParams(options?)
- Args
- options: Object containing one of the following options
- useDefaults: (optional array) An array containing a list of param keys to use default values
- e.g. ["param3"] <- if param3 has a default value, it will be used when an error is thrown while decoding
- defaults: (optional object) Specify the default values that are returned if it fails to decode a specific param key value
- e.g. { param3: [0] } <- param3 will default to '[0]' if it attempted to decode an invalid value and threw an error
- useDefaults: (optional array) An array containing a list of param keys to use default values
- options: Object containing one of the following options
- Returns: Object containing the below key/value pairs
- values: (object) Contains the values of the param keys that were successfully decoded
- e.g. { param3: [10, 30] } <- param3 will be a array of number | undefined
- errors: (object) Contains error data about the param keys that failed to be decoded
- e.g. { param3: { expectedType: "numberArray", actualType: "number", errorStringValue: "15" } }
- values: (object) Contains the values of the param keys that were successfully decoded
- Args
- clearQueryParams(options?)
- Args
- options: Object containing one of the following options
- behavior: (optional string) Specify either "replace" to replace the entry in the browser history, or "push" to add to the history
- include: (optional array) Specify the param keys to include only when clearing the query params
- e.g. ["param1", "param3"] <- param1/param3 only will be removed from the URL
- exclude: (optional array) Specify the param keys to exclude when clearing the query params (takes precedence over include array, if include is not provided, it will clear the other params)
- e.g. ["param1", "param3"] <- param2/param4 only will be removed from the URL and param1/param3 will be left
- options: Object containing one of the following options
- Returns: void
- Args
No vulnerabilities found.
No security vulnerabilities found.
Other packages similar to react-nav-query-params
use-nav-state
React State that update and it's updated by Query Params
@render-with/react-router
Render decorators for components under test that require a React Router or Routes.
@cultivateit/decorate-with-react-router
Render decorators for components under test that require a React Router.