This post was originally posted on my blog

Last time, I got more than 500 likes on Zhihu after I finished the four front-end handwriting, which really made me feel flattered. On the one hand, I want to review React Hooks, on the other hand, I want to share with you some of my own experiences learning React Hooks. Because of my limitations, I will share some basic tips on how to use React Hooks. I will update you on the principles of Hooks in the future.

Let’s take a look at the byte interview question, the topic is to implement a custom Hook, click to switch state.

function SomeComponent() {
  const [state, toggleState] = useToggle(false);
  return <div>
    {state ? 'true' : 'false'}
    <button onClick={toggleState}></button>
  </div>
}

// Implement useToggle
function useToggle(initialValue) {
    const [value, setValue] = useState(initialValue);
    const toggle = () = >{setValue(! value)};return [value, toggle];
}
Copy the code

Which are the seven Hooks

  1. useStatestate
  2. useEffectThe hook, and its brotheruseLayoutEffect
  3. useContextcontext
  4. useReducerInstead of a story
  5. useMemoThe cache, and its little brotheruseCallback
  6. useRefreference
  7. Customize the Hookhybrid

useState

Const [X, setX] = react.usestate (initial value of X)

A simple example:

function App() {
  const [user,setUser] = useState({name:'Varian'.age: 18})
  const onClick = () = >{
    setUser({
      name: 'Janye'})}return (
    <div className="App">
      <h1>{user.name}</h1>
      <h2>{user.age}</h2>
      <button onClick={onClick}>Click</button>
    </div>
  );
}
Copy the code

We can see that when we click the button, age disappears, but we just changed the name. Why?

In simple terms, it’s two completely unrelated objects.

React creates a new virtual DOM object when the data changes, and then performs a DOM Diff with the original virtual DOM to create a minimal change Patch. Render the Patch on the page. Diff found that the new object did not have the age property, so I removed it.

There are two things to be aware of when using useState:

  1. To get the original value, you have to copy it in setX, something like thatsetUser({... user, name: 'Janye'})
  2. When setX(obj), the address of obj must change

useEffect

UseEffect is primarily used to solve the problem of how function components use lifecycle hooks as class components do.

It has three usage scenarios:

  1. Used as componentDidMount, the second argument is an empty array[]
  2. Used as componentDidUpdate, the second argument specifies the dependency
  3. Used as componentWillUnmount, via return

Here’s the simplest example:

const BlinkyRender = () = > {
  const [value, setValue] = useState(0);

  useEffect(() = > {
    document.querySelector('#x').innerText = `value: 1000`
  }, [value]);

  return (
    <div id="x" onClick={()= > setValue(0)}>value: {value}</div>
  );
};

ReactDOM.render(
  <BlinkyRender />.document.querySelector("#root"));Copy the code

So how is it different from its cousin, useLayoutEffect? UseEffect is executed after the browser renders, useLayoutEffect is executed before the browser renders, useLayoutEffect is always executed before useEffect.

So for the user experience (see first render first), we should usually useEffect first.

useContext

If we want to share state between components, we can use useContext.

Its use can be divided into three steps:

  1. useC = createContext(initial)Create context
  2. use<C.provider>Define the scope
  3. Used within scopeuseContext(C)To use context

A simple example:

const C = createContext(null);

function App() {
  console.log("App executes.");
  const [n, setN] = useState(0);
  return (
    <C.Provider value={{ n.setN}} >
      <div className="App">
        <Baba />
      </div>
    </C.Provider>
  );
}

function Baba() {
  const { n, setN } = useContext(C);
  return (
    <div>I am the father n: {n}<Child />
    </div>
  );
}

function Child() {
  const { n, setN } = useContext(C);
  const onClick = () = > {
    setN(i= > i + 1);
  };
  return (
    <div>I'm the son and I get n: {n}<button onClick={onClick}>+ 1</button>
    </div>
  );
}
Copy the code

useReducer

UseReducer is a replacement for Redux, or an enhanced version of useState, if you have to explain it in one sentence.

In terms of usage, there are four steps:

  1. Create the initial value initialState
  2. Create all operations Reducer (state, action)
  3. Pass it to useReducer to get the read and write API
  4. callWrite ({type: 'operation type '})

Here’s a basic example:

const initial = {
  n: 0
};

const reducer = (state, action) = > {
  if (action.type === "add") {
    return { n: state.n + action.number };
  } else if (action.type === "multi") {
    return { n: state.n * 2 };
  } else {
    throw new Error("unknown type"); }};function App() {
  const [state, dispatch] = useReducer(reducer, initial);
  const { n } = state;
  const onClick = () = > {
    dispatch({ type: "add".number: 1 });
  };
  const onClick2 = () = > {
    dispatch({ type: "add".number: 2 });
  };
  return (
    <div className="App">
      <h1>n: {n}</h1>

      <button onClick={onClick}>+ 1</button>
      <button onClick={onClick2}>+ 2</button>
    </div>
  );
}
Copy the code

useMemo

Basic syntax: useMemo(callback function, [dependency])

Similar to Vue’s computed property, computed, useMemo has the ability to cache and re-render depending on changes.

The only difference between useCallback and useMemo is that useMemo can cache all objects, whereas useCallback can only cache functions.

UseCallback (x = > log (x), [m]) is equivalent to useMemo (() = = > > x log (x), [m])

useRef

The main function is to create a reference to the data and keep it constant throughout the render process.

Const count = useRef(0)

Here’s an example of how I encapsulated Echarts:

export function ReactEcharts(props) {
  const {option, loading} = props
  const container = useRef(null)
  const chart = useRef(null)

  useEffect(() = > {
    const width = document.documentElement.clientWidth
    const c = container.current
    console.log(c)
    c.style.width = `${width - 20}px`
    c.style.height = `${(width - 20) * 1.2}px`
    chart.current = echarts.init(c, 'dark')}, [])// [] - mounted on first time

  useEffect(() = > {
    chart.current.setOption(option)
  }, [option]) // When option change is similar to vue watch

  useEffect(() = > {
    if (loading) chart.current.showLoading()
    else chart.current.hideLoading()
  }, [loading])
  return (
    <div ref={container}/>)}Copy the code

Customize the Hook

We can mix the above hooks according to actual requirements and encapsulate them into a function, giving a simple example:

const useList = () = > {
  const [list, setList] = useState(null);
  useEffect(() = > {
    ajax("/list").then(list= >{ setList(list); }); } []);// [] Make sure to run only the first time
  return {
    list: list,
    setList: setList
  };
};
export default useList;
Copy the code

Write in the last

Based on my recent interview experience, I have two thoughts to share with you:

  1. The learning and improvement of technology cannot be separated from persistent practice. It is necessary to constantly review the old and learn new things to overcome the forgetting curve.
  2. Make good use of every opportunity to communicate with the interviewer, for their unfamiliar knowledge points for timely reflection and review, to further improve their knowledge system.