├── .gitignore ├── .npmignore ├── README.md ├── package-lock.json ├── package.json ├── src └── index.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /lib 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server Only Context 2 | 3 | Tiny wrapper around `cache` to have request-scoped context 4 | for server components. No more prop drilling! 5 | 6 | **Note:** when navigating on the client side the layout is not re-rendered, 7 | so you need to set the context **both in the page and in the layout**. 8 | 9 | ```javascript 10 | import serverContext from "server-only-context"; 11 | 12 | export const [getLocale, setLocale] = serverContext("en"); 13 | export const [getUserId, setUserId] = serverContext(""); 14 | ``` 15 | 16 | ```javascript 17 | import { setLocale, setUserId } from "@/context"; 18 | 19 | export default function UserPage({ params: { locale, userId } }) { 20 | setLocale(locale); 21 | setUserId(userId); 22 | return ; 23 | } 24 | ``` 25 | 26 | ```javascript 27 | import { getLocale, getUserId } from "@/context"; 28 | 29 | export default function MyComponent() { 30 | const locale = getLocale(); 31 | const userId = getUserId(); 32 | 33 | return ( 34 |
35 | Hello {userId}! Locale is {locale}. 36 |
37 | ); 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-only-context", 3 | "version": "0.1.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "server-only-context", 9 | "version": "0.1.0", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "typescript": "^4.9.5" 13 | }, 14 | "peerDependencies": { 15 | "react": "next" 16 | } 17 | }, 18 | "node_modules/js-tokens": { 19 | "version": "4.0.0", 20 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 21 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 22 | "peer": true 23 | }, 24 | "node_modules/loose-envify": { 25 | "version": "1.4.0", 26 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 27 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 28 | "peer": true, 29 | "dependencies": { 30 | "js-tokens": "^3.0.0 || ^4.0.0" 31 | }, 32 | "bin": { 33 | "loose-envify": "cli.js" 34 | } 35 | }, 36 | "node_modules/react": { 37 | "version": "18.3.0-next-fccf3a9fb-20230213", 38 | "resolved": "https://registry.npmjs.org/react/-/react-18.3.0-next-fccf3a9fb-20230213.tgz", 39 | "integrity": "sha512-DPWHyL/tLt70h3CW8So5ul1pnW0muvZFM3B8iwxVj+u4j4Z901wnbwE45CLMSpX8yJiSxO9ioPvkhgiuIji2uw==", 40 | "peer": true, 41 | "dependencies": { 42 | "loose-envify": "^1.1.0" 43 | }, 44 | "engines": { 45 | "node": ">=0.10.0" 46 | } 47 | }, 48 | "node_modules/typescript": { 49 | "version": "4.9.5", 50 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 51 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 52 | "dev": true, 53 | "bin": { 54 | "tsc": "bin/tsc", 55 | "tsserver": "bin/tsserver" 56 | }, 57 | "engines": { 58 | "node": ">=4.2.0" 59 | } 60 | } 61 | }, 62 | "dependencies": { 63 | "js-tokens": { 64 | "version": "4.0.0", 65 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 66 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 67 | "peer": true 68 | }, 69 | "loose-envify": { 70 | "version": "1.4.0", 71 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 72 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 73 | "peer": true, 74 | "requires": { 75 | "js-tokens": "^3.0.0 || ^4.0.0" 76 | } 77 | }, 78 | "react": { 79 | "version": "18.3.0-next-fccf3a9fb-20230213", 80 | "resolved": "https://registry.npmjs.org/react/-/react-18.3.0-next-fccf3a9fb-20230213.tgz", 81 | "integrity": "sha512-DPWHyL/tLt70h3CW8So5ul1pnW0muvZFM3B8iwxVj+u4j4Z901wnbwE45CLMSpX8yJiSxO9ioPvkhgiuIji2uw==", 82 | "peer": true, 83 | "requires": { 84 | "loose-envify": "^1.1.0" 85 | } 86 | }, 87 | "typescript": { 88 | "version": "4.9.5", 89 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 90 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 91 | "dev": true 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-only-context", 3 | "version": "0.1.0", 4 | "description": "Context for your server components", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "lib/**/*" 8 | ], 9 | "scripts": { 10 | "prepare": "tsc", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/manvalls/server-only-context.git" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/manvalls/server-only-context/issues" 22 | }, 23 | "homepage": "https://github.com/manvalls/server-only-context#readme", 24 | "peerDependencies": { 25 | "react": "next" 26 | }, 27 | "devDependencies": { 28 | "typescript": "^4.9.5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { cache } from "react"; 3 | 4 | export default (defaultValue: T): [() => T, (v: T) => void] => { 5 | const getRef = cache(() => ({ current: defaultValue })); 6 | 7 | const getValue = (): T => getRef().current; 8 | 9 | const setValue = (value: T) => { 10 | getRef().current = value; 11 | }; 12 | 13 | return [getValue, setValue]; 14 | }; 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./lib", 7 | "strict": true 8 | }, 9 | "include": ["src"], 10 | "exclude": ["node_modules", "**/__tests__/*"] 11 | } --------------------------------------------------------------------------------