From 182910bb4b2b1a988ccaf6a13658c2a3e31aa8b1 Mon Sep 17 00:00:00 2001 From: Jakub Biesiada Date: Sun, 10 Oct 2021 00:47:47 +0200 Subject: [PATCH] chore: update --- .husky/.gitignore | 1 - .husky/_/husky.sh | 30 ++++++++++++++++++++++ .husky/pre-commit | 4 +++ .npmignore | 3 +-- CHANGELOG.md | 4 +-- README.md | 12 ++++----- __tests__/useGroupState.test.ts | 4 +++ package.json | 45 +++++++++++++++------------------ src/useGroupState.ts | 35 ++++++++++++++++++------- 9 files changed, 94 insertions(+), 44 deletions(-) delete mode 100644 .husky/.gitignore create mode 100644 .husky/_/husky.sh create mode 100755 .husky/pre-commit diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec..0000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.husky/_/husky.sh b/.husky/_/husky.sh new file mode 100644 index 0000000..ca2720e --- /dev/null +++ b/.husky/_/husky.sh @@ -0,0 +1,30 @@ +#!/bin/sh +if [ -z "$husky_skip_init" ]; then + debug () { + [ "$HUSKY_DEBUG" = "1" ] && echo "husky (debug) - $1" + } + + readonly hook_name="$(basename "$0")" + debug "starting $hook_name..." + + if [ "$HUSKY" = "0" ]; then + debug "HUSKY env variable is set to 0, skipping hook" + exit 0 + fi + + if [ -f ~/.huskyrc ]; then + debug "sourcing ~/.huskyrc" + . ~/.huskyrc + fi + + export readonly husky_skip_init=1 + sh -e "$0" "$@" + exitCode="$?" + + if [ $exitCode != 0 ]; then + echo "husky - $hook_name hook exited with code $exitCode (error)" + exit $exitCode + fi + + exit 0 +fi diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..d0612ad --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npm run pre-commit diff --git a/.npmignore b/.npmignore index dc58000..aa6ba0e 100755 --- a/.npmignore +++ b/.npmignore @@ -1,11 +1,10 @@ src __tests__ coverage - +.husky tsconfig.json .travis.yml .prettierrc - .eslintrc.js rollup.config.js yarn-error.log diff --git a/CHANGELOG.md b/CHANGELOG.md index 008fba4..eea5db9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,6 @@ ## 1.0.0 (Soon) -#### New Feature +### New Feature -- added `useGroupState` hook +- added the `useGroupState` hook diff --git a/README.md b/README.md index cb3a643..aa26309 100755 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ [![NPM downloads](https://img.shields.io/npm/dm/react-group-state?style=flat-square)](https://www.npmjs.com/package/react-group-state) [![NPM license](https://img.shields.io/npm/l/react-group-state?style=flat-square)](https://www.npmjs.com/package/react-group-state) [![Codecov](https://img.shields.io/codecov/c/github/cool-hooks/react-group-state?style=flat-square)](https://codecov.io/gh/cool-hooks/react-group-state) -[![Travis](https://img.shields.io/travis/com/cool-hooks/react-group-state/main?style=flat-square)](https://travis-ci.com/cool-hooks/react-group-state) +[![Travis](https://img.shields.io/travis/com/cool-hooks/react-group-state/main?style=flat-square)](https://app.travis-ci.com/github/cool-hooks/react-group-state) [![Bundle size](https://img.shields.io/bundlephobia/min/react-group-state?style=flat-square)](https://bundlephobia.com/result?p=react-group-state) ## About -Use state management style from React class components in function components +Use the state management style from React class components in function components ### Idea @@ -17,7 +17,7 @@ Use state management style from React class components in function components ### Demo -**[Playground – play with library in CodeSandbox](https://codesandbox.io/s/react-group-state-q4iss)** +**[Playground – play with the library in CodeSandbox](https://codesandbox.io/s/react-group-state-q4iss)** ### Alternatives @@ -39,7 +39,7 @@ $ yarn add react-group-state ## Getting Started -• Import hook in React application file: +• Import a hook in a React application file: ```js import { useGroupState } from 'react-group-state'; @@ -58,11 +58,11 @@ import { useGroupState } from 'react-group-state'; | Name | Type | Description | | ------------ | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **state** | object | State | -| **setState** | (object or (prevState) => object, (newState) => void) | Function to set new state where **the first parameter** is new object or function with previous state that returns object and **second parameter** where value passed to function is updated state | +| **setState** | (object or (prevState) => object, (newState) => void) | A function to set a new state, where the **first parameter** is a new object or a function with the previous state, which returns the object and **the second parameter**, where the value passed to the function is the updated state | ## Example -**• Use `useGroupState` Hook:** +**• Use the `useGroupState` Hook:** ```jsx import React from 'react'; diff --git a/__tests__/useGroupState.test.ts b/__tests__/useGroupState.test.ts index 3454347..68e0e32 100644 --- a/__tests__/useGroupState.test.ts +++ b/__tests__/useGroupState.test.ts @@ -92,4 +92,8 @@ describe('useGroupState', () => { expect(state).toBe(initialState); }); + + it.todo('should extend default object structure'); + it.todo('should strict'); + it.todo('should overwrite schema'); }); diff --git a/package.json b/package.json index 81a0822..f3777b6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-group-state", "version": "1.0.0-beta.3", - "description": "Use state management style from React class components in function components", + "description": "Use the state management style from React class components in function components", "author": "Jakub Biesiada", "license": "MIT", "main": "lib/react-group-state.cjs.js", @@ -17,7 +17,9 @@ "lint": "eslint 'src/**/*.ts' --fix", "prettier": "prettier --write 'src/**/*.ts'", "commit": "git-cz", - "semantic-release": "semantic-release" + "semantic-release": "semantic-release", + "prepare": "husky install", + "pre-commit": "lint-staged" }, "repository": { "type": "git", @@ -35,32 +37,32 @@ }, "homepage": "https://github.com/cool-hooks/react-group-state#readme", "devDependencies": { - "@rollup/plugin-node-resolve": "^13.0.0", - "@semantic-release/git": "^9.0.0", - "@testing-library/react-hooks": "^7.0.0", - "@types/jest": "^26.0.23", - "@types/react": "^17.0.8", - "@typescript-eslint/parser": "^4.25.0", + "@rollup/plugin-node-resolve": "^13.0.5", + "@semantic-release/git": "^10.0.0", + "@testing-library/react-hooks": "^7.0.2", + "@types/jest": "^27.0.2", + "@types/react": "^17.0.27", + "@typescript-eslint/parser": "^4.33.0", "cz-conventional-changelog": "3.3.0", "cz-emoji": "^1.3.1", - "eslint": "^7.27.0", + "eslint": "^8.0.0", "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", - "eslint-plugin-react": "^7.23.2", + "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-react": "^7.26.1", "eslint-plugin-react-hooks": "^4.2.0", - "husky": "^6.0.0", - "jest": "^26.6.3", - "lint-staged": "^11.0.0", - "prettier": "^2.3.0", + "husky": "^7.0.2", + "jest": "^27.2.5", + "lint-staged": "^11.2.2", + "prettier": "^2.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-test-renderer": "^17.0.2", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.30.0", - "semantic-release": "^17.4.3", - "semantic-release-gitmoji": "^1.3.4", - "ts-jest": "^26.5.4", - "typescript": "^4.3.2" + "semantic-release": "^18.0.0", + "semantic-release-gitmoji": "^1.4.2", + "ts-jest": "^27.0.5", + "typescript": "^4.4.3" }, "peerDependencies": { "react": ">=16.8.0" @@ -75,11 +77,6 @@ "^.+\\.tsx?$": "ts-jest" } }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, "lint-staged": { "src/**/*.ts": [ "npm run prettier", diff --git a/src/useGroupState.ts b/src/useGroupState.ts index b80cd23..0b0c601 100644 --- a/src/useGroupState.ts +++ b/src/useGroupState.ts @@ -6,8 +6,10 @@ type UpdateStateCallback = ( ) => void; const defaultOptions = { - extendable: false, // new fields - strict: true, // other types for field + extendable: true, // new fields + strict: false, // other types for field + overwrite: false, + // fallback: undefined, // -> fallback for overwrite }; export function useGroupState( @@ -15,7 +17,7 @@ export function useGroupState( options?: typeof defaultOptions ) { // TODO add logic for options - const { extendable, strict } = { + const { extendable, strict, overwrite } = { ...defaultOptions, ...options, }; @@ -23,25 +25,40 @@ export function useGroupState( const [state, setState] = useState(group); const updateState = useCallback>( - (data, callback) => { + (data, callback, _options) => { const updatedState = state; // TODO? replace with prev state const mergeState = (data: Partial) => { (Object.keys(data) as Array).map((key) => { - if (Object.prototype.hasOwnProperty.call(updatedState, key)) { - updatedState[key] = data[key] as T[keyof T]; + if ( + extendable || + (!extendable && + Object.prototype.hasOwnProperty.call(updatedState, key)) + ) { + // TODO compare objects/arrays/etc + if ( + !strict || + (strict && typeof updatedState[key] === typeof data[key]) + ) { + updatedState[key] = data[key] as T[keyof T]; + } } }); - setState((prevState) => ({ ...prevState, ...updatedState })); - // setState({ ...updatedState }); + setState((prevState) => { + if (overwrite) { + return data; + } + + return { ...prevState, ...updatedState }; + }); callback?.(updatedState); }; mergeState(typeof data === 'function' ? data(state) : data); }, - [state] + [extendable, overwrite, state, strict] ); return [state, updateState] as const;