scope-value-hook.js 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. import { useCallback, useEffect, useState } from 'react'
  2. import PropTypes from 'prop-types'
  3. import _ from 'lodash'
  4. import { useIdeContext } from '../ide-context'
  5. /**
  6. * Binds a property in an Angular scope making it accessible in a React
  7. * component. The interface is compatible with React.useState(), including
  8. * the option of passing a function to the setter.
  9. *
  10. * @param {string} path - dot '.' path of a property in the Angular scope.
  11. * @param {boolean} deep
  12. * @returns {[any, function]} - Binded value and setter function tuple.
  13. */
  14. export default function useScopeValue(path, deep = false) {
  15. const { $scope } = useIdeContext({
  16. $scope: PropTypes.object.isRequired,
  17. })
  18. const [value, setValue] = useState(() => _.get($scope, path))
  19. useEffect(() => {
  20. return $scope.$watch(
  21. path,
  22. newValue => {
  23. setValue(deep ? _.cloneDeep(newValue) : newValue)
  24. },
  25. deep
  26. )
  27. }, [path, $scope, deep])
  28. const scopeSetter = useCallback(
  29. newValue => {
  30. setValue(val => {
  31. const actualNewValue = _.isFunction(newValue) ? newValue(val) : newValue
  32. $scope.$applyAsync(() => _.set($scope, path, actualNewValue))
  33. return actualNewValue
  34. })
  35. },
  36. [path, $scope]
  37. )
  38. return [value, scopeSetter]
  39. }