You should know about hooks

What you should know about the use of hooks, you can have a look

First, let's take the first hook example.

const count=useCounter()
//This hook was called elsewhere
function useCounter(){
console.log('Called count')
// This is printed every time
const [count,setCount]=useState(0)
// useEffect(()=>{
//     setInterval(() => {
//         console.log('useCounter',count)
//         setCount(count + 1);
//     }, 1000);      
// },[])
// The count here takes the value when the useEffect is initially executed,
// That is, 0, so every addition starts from 0,
// So the value here should always be 0
// useEffect(()=>{
//     let id=setInterval(() => {
//         console.log('useCounter',count)
//         setCount(count + 1);
//     }, 1000);
// },[count])
// setInterval is redefined every time it is re executed,
// So you need a global variable to save this thing, such as a ref,
// Or use the function mode to set count
    useEffect(()=>{
let id=setInterval(() => {
console.log('useCounter',count)
            setCount(c=>c+1);
        }, 1000);
// There is no need to pass in dependencies. It is only executed once, and setInterval will not be reset,
// The function setting method of setCount can achieve our effect
    },[])
// Or hang it on a ref globally
return [count]
}

It can be seen that every rendering of hook will go into hook.

  • It seems that because the count value will change and is referenced outside, the useCounter function will be rendered again every time.

  • But the useEffect in this will only be called once.

Each rendering has its own event handler, including the parameters passed in

  • Our component function will be called every time it is rendered. The count of each call is constant, and it is given the state value in the current rendering. Therefore, if the function depends on external parameters, it is necessary to pass the parameters into the second parameter. When the parameters change, let the function be recreated.

  • Each rendering has a "new version" of handleClick, and each version of handleClick remembers its own event.

  • vue is more like storing all data in one place. Every time you use parameters, you go there to find the latest one. Once this function is defined, it will remain unchanged.

  • In any rendering, props and state are always the same. Props and state are independent of each other in different rendering, so any value used to them is also independent of each other. They all belong to a specific rendering. Even asynchronous function calls in event processing "see" the values in this rendering. It may not be the latest value.

effect: each rendering has its own effects

  • It is not that the count value changes in the "constant" effect, but the effect function itself is different in each rendering. If the effect depends on the external count value, each version of the effect should be created according to the latest count.

  • Although the effect is a, each rendering is a different function, and the props or state obtained by each effect function comes from the specific rendering that belongs to it.

  • The time at which the effect is rendered.

function Counter() {
  // ...
  useEffect(
    // Effect function from first render
    () => {
      document.title = `You clicked ${0} times`;
    }
  );
  // ...
}

// UI when rendering status is 0.

// Content to render: < p > you clicked 0 times < / P >.
// Call this after rendering.
// () => { document.title = 'You clicked 0 times' }. 
// Start updating the UI and adding something to the DOM.
// Draw to the screen.
// Run the effect given to me

// Run () = > {document. Title = 'you clicked 0 times'}.

// Initial rendering
function Counter() {
  // ...
  useEffect(
    // Effect function from second render
    () => {
      document.title = `You clicked ${1} times`;
    }
  );
  // ...
}

// React: UI when rendering state is 1.

// Content to render: < p > you clicked 1 times < / P >.
// After rendering, call.
// effect: () => { document.title = 'You clicked 1 times' }. 
// Started updating the UI and modified the DOM.
// The changes are drawn on the screen.
// Run render effect

// Run () = > {document. Title = 'you clicked 1 times'}.
function Counter() {
  // ...
  useEffect(
    // Effect function from third render
    () => {
      document.title = `You clicked ${2} times`;
    }
  );
  // ..
}

1 . All effects will be executed successively after rendering. Conceptually, it is only a part of the component output, and you can see the props and state of a specific rendering.
2 . The difference from this is the previous this state. Count, in this mode, only the latest data will be obtained.

effect cleans up the last function

// Wrong understanding:
// Suppose that props is {id: 10} when rendering for the first time,
// The second rendering is {id: 20}

// The effect of {id: 10} is cleared.
// Render UI for {id: 20}.
// Run the effect of {id: 20}

// correct
// Render UI for {id: 20}.
// The UI of {id: 20} can be seen on the screen.
// Clear the effect of {id: 10}.
// Run the effect of {id: 20}.
// Clearing the effect does not read the latest props,
// He can only read the props value that defines his rendering
  • react will synchronize to DOM according to our current props and state.

  • useEffect enables you to synchronize things outside the react tree according to props and state.

  • react cannot distinguish between effects, so in order to avoid repeated calls, you can give useEffect a dependent array parameter.

useEffect(() => {
    document.title = 'Hello, ' + name;
  }, [name]); // Our deps
// Ensure that only the name in the rendering is used

// If these dependencies in the current rendering have the same values as when the effect was last run,
// Because nothing needs to be synchronized, React will automatically skip this effect:
  • Even if only one value in the dependency array is different in the two renderings, the operation of the effect will not be skipped and all will be synchronized

Common ways to remove dependencies

1. Make Effect self-sufficient, but this use scenario is extremely preferred. Gave up the right to modify the state outside.

useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
}, [count]);

useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    return () => clearInterval(id);
}, []);

2. Use reducer to decouple the two processes of behavior and operating data. When you dispatch, React just remembers the action - it will call reducer again in the next rendering. At that time, the new props can be accessed, and the reducer call is not in the effect.

That's why I tend to think useReducer is Hooks's "cheating mode". It separates the update logic from describing what happened. As a result, this helps me remove unnecessary dependencies and avoid unnecessary effect calls.

3. Move the function to effects

function SearchResults() {
  const [query, setQuery] = useState('react');
  useEffect(() => {
    function getFetchUrl() {
      return 'https://hn.algolia.com/api/v1/search?query=' + query;
    }
    // This effect depends on function 1
    async function fetchData() {
      const result = await axios(getFetchUrl());
        setData(result.data);
    }
    // Function 2 since this effect
    fetchData();
  }, [query]); // OK
  // ...
}

4 . It can't be put into effects

// useEffect executed only once
function SearchResults() {
  function getFetchUrl(query) {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }

  useEffect(() => {
    const url = getFetchUrl('react');
    ...
  }, []);

// No dependency is used. It is only executed once during initialization,
  useEffect(() => {
    const url = getFetchUrl('redux');
    ...
  }, []);
  ...
}

// What happens when functions are used as dependencies?
function SearchResults() {
  function getFetchUrl(query) {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }

  useEffect(() => {
    const url = getFetchUrl('react');
  }, [getFetchUrl]);

  useEffect(() => {
    const url = getFetchUrl('redux');
  }, [getFetchUrl]);
}
//Each rendering function is actually new, so this dependency is completely obsolete,
// In fact, each refresh triggers the effect execution, that is, requesting data
// Solution 1: if a function does not use any value in the component,
// Just refer it to the definition outside the component, and then it can be freely used in the effect
function getFetchUrl(query) {
  return 'https://hn.algolia.com/api/v1/search?query=' + query;
}

function SearchResults() {
  useEffect(() => {
    const url = getFetchUrl('react');
  }, []);

  useEffect(() => {
    const url = getFetchUrl('redux');
  }, []);
  // At this time, it is no longer necessary to set it as dependency because it is not in the rendering range,
  // It will not be affected by data flow and will not change due to props and state
}

//Solution 2: package as usecallback hook
function SearchResults() {
  const getFetchUrl = useCallback((query) => {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }, []);

  useEffect(() => {
    const url = getFetchUrl('react');
  }, [getFetchUrl]);

  useEffect(() => {
    const url = getFetchUrl('redux');
  }, [getFetchUrl]);
  // In essence, it adds a layer of dependency checking to the function. Only the parameters of the function dependency change,
  // The function will change, rather than simply removing the dependence of the function,
  // Is it possible to check the effect dependency array in this way??
}

Previous reading

1. Introduction to React Hooks

2. React Hooks overview

3. Use State Hook

4. Use Effect Hook

5. Hooks usage rules

6,Customize Hook

Keywords: Javascript Front-end React

Added by aktell on Sat, 08 Jan 2022 03:08:55 +0200