What is the angular's $watch function equivalent in React.js?
I want to listen state changes and call a function like getSearchResults().
componentDidMount: function() { this.getSearchResults(); } What is the angular's $watch function equivalent in React.js?
I want to listen state changes and call a function like getSearchResults().
componentDidMount: function() { this.getSearchResults(); } The following lifecycle methods will be called when state changes. You can use the provided arguments and the current state to determine if something meaningful changed.
componentWillUpdate(object nextProps, object nextState) componentDidUpdate(object prevProps, object prevState) componentDidUpdate in the component with the prop was the right prescription. Thanks for this.componentWillUpdate is being deprecated: reactjs.org/blog/2018/03/27/update-on-async-rendering.htmlcomponentDidUpdate not also fire when receiving new props, not necessarily just when state changes?componentWillUpdate is deprecated.In 2020 you can listen to state changes with the useEffect hook like this
export function MyComponent(props) { const [myState, setMyState] = useState('initialState') useEffect(() => { console.log(myState, '- Has changed') },[myState]) // <-- here put the parameter to listen, react will re-render component when your state will be changed } useEffect itself always causes an additional render – is there a way to avoid that?useEffect (i.e [myState] in the example above) the component will only rerender if one of the variables in the dependency array has changed.I haven't used Angular, but reading the link above, it seems that you're trying to code for something that you don't need to handle. You make changes to state in your React component hierarchy (via this.setState()) and React will cause your component to be re-rendered (effectively 'listening' for changes). If you want to 'listen' from another component in your hierarchy then you have two options:
count changes from 20 to 21) and run some code when it changes. useEffect does this in React hooks. Not sure what the mechanism was before React hooks, or if there was one.Since React 16.8 in 2019 with useState and useEffect Hooks, following are now equivalent (in simple cases):
AngularJS:
$scope.name = 'misko' $scope.$watch('name', getSearchResults) <input ng-model="name" /> React:
const [name, setName] = useState('misko') useEffect(getSearchResults, [name]) <input value={name} onChange={e => setName(e.target.value)} /> I think you should be using below Component Lifecycle as if you have an input property which on update needs to trigger your component update then this is the best place to do it as its will be called before render you even can do update component state to be reflected on the view.
componentWillReceiveProps: function(nextProps) { this.setState({ likesIncreasing: nextProps.likeCount > this.props.likeCount }); } If you use hooks like const [ name , setName ] = useState (' '), you can try the following:
useEffect(() => { console.log('Listening: ', name); }, [name]); Using useState with useEffect as described above is absolutely correct way. But if getSearchResults function returns subscription then useEffect should return a function which will be responsible for unsubscribing the subscription . Returned function from useEffect will run before each change to dependency(name in above case) and on component destroy
It's been a while but for future reference: the method shouldComponentUpdate() can be used.
An update can be caused by changes to props or state. These methods are called in the following order when a component is being re-rendered:
static getDerivedStateFromProps() shouldComponentUpdate() render() getSnapshotBeforeUpdate() componentDidUpdate() shouldComponentUpdate so it might not be suitable for this use case.I use this code to see which one in the dependencies changes. This is better than the pure useEffect in many cases.
// useWatch.js import { useEffect, useMemo, useRef } from 'react'; export function useWatchStateChange(callback, dependencies) { const initialRefVal = useMemo(() => dependencies.map(() => null), []); const refs = useRef(initialRefVal); useEffect(() => { for(let [index, dep] of dependencies.entries()) { dep = typeof(dep) === 'object' ? JSON.stringify(dep) : dep; const ref = refs.current[index]; if(ref !== dep) { callback(index, ref, dep); refs.current[index] = dep; } } // eslint-disable-next-line react-hooks/exhaustive-deps }, dependencies); } And in my React component
// App.js import { useWatchStateChange } from 'useWatch'; ... useWatchStateChange((depIndex, prevVal, currentVal) => { if(depIndex !== 1) { return } // only focus on dep2 changes doSomething("dep2 now changes", dep1+dep2+dep3); }, [ dep1, dep2, dep3 ]); useEffect in many cases, and which cases are these?useEffect hook doesn't tell you which dependencies are updated/changed, but my custom useWatchStateChange hook gives more details over which dependencies are changes so we have more control over the logic in the code.