React hooks Detailed

This article is only a summary of the entry-hooks, veterans skip it ~

React From 16.8.X added a new feature, react hooks let us look at this new feature brings what a surprise it ~ the following we take a different approach to creating a component comparison summary

Way to create components:

Used react are aware, the traditional react create component provides two ways, with functional class (class)

class creation of the state assembly

class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <div>
      <p>{this.props.name}</p>
    </div>
  }
}

function renderApp() {
  let appProps = {
    name: 'dqhan'
  }
  ReactDOM.render(
    <App  {...appProps} />,
    document.getElementById('app')
  )
}

renderApp();

Add state management

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: props.name
    };
    this.handleChangeName = this.handleChangeName.bind(this);
  }

  handleChangeName() {
    this.setState({
      name: '我变了'
    })
  }

  render() {
    return (
      <React.Fragment>
        <p> {`hello~${this.state.name}`} </p>
        <button onClick={this.handleChangeName}></button>
      </React.Fragment>
    );
  }
}

We can achieve a stateless components and assemblies by conventional state setState management through class.

Creating functional components

function App(props) {
  return <p>{`hello! ${props.name}`}</p>
}

function renderApp() {
  let appProps = { name: "dqhan" };
  ReactDOM.render(<App {...appProps} />, document.getElementById("app"));
}

Creating functional components are usually stateless components, this way there is no way within the unified state management, state management if we have to add it, it can only be achieved by means of a publish-subscribe redux friends - or our own use of the Observer pattern (emmmm more reluctant, after all, we can not do the actual development)

So if we have to do it, the question came, React version after 16.8.X added a new feature is the hooks.

API hooks involved have useState, useEffect, useCallback, useRef, useMemo, React.memo, useReducer, and specifically refer to the official documentation, we look at how to use hooks

React Hooks create components

Stateless components

function App(props) {
  return <div>
    <p>{`hello~${props.name}`}</p>
  </div>
}

Haha, with functional, like, after all, we want to add state management in functional components in Well

1.useState

: Addition of state management

function App() {
  let [name, setName] = useState('dqhan');
  return <div>
    <p>{`hello~${name}`}</p>
    <button onClick={() => setName('我变了')}>Click</button>
  </div>;
}

react hook can manage their own state, with its own hook function, this is compared to the functional obviously better, without the help of redux, this is why we would like to mention functional programming involves state management issues at the front, that is, to compare with react hook to be here.

Here we know the useState, more than a useState let create functional class has its own persistent state. Then the functional components inside how we do in class setState it?

function App(props) {
  let [name, setName] = useState('dqhan');
  let handleChangeName = useCallback(() => {
    setName(preState => {
      let updatedValues = {
        newValue: '我变了'
      }
      return { ...{ preState }, ...updatedValues }
    })
  })
  function click1(params) {
    setName('我变了1')
  }
  return <div>
    <p>{`hello~${name}`}</p>
    <button onClick={handleChangeName}>Click1</button>
    <button onClick={click1}>Click2</button>
  </div>;
}

This has been achieved in the way the state of integration, but if we simulate a state of it, to the unified management of state it, so we can achieve

function App(props) {
  let [state, setState] = useState({
    name: 'dqhan'
  });
  let handleChangeName = useCallback(() => {
    setState(preState => {
      let updatedValues = {
        name: '我变了'
      }
      return { ...preState, ...updatedValues }
    })
  })
  return <div>
    <p>{`hello~${state.name}`}</p>
    <button onClick={handleChangeName}>Click</button>
  </div>;
}

So far, already know how to use react hook state, then a periodic function of it, then it involves another hook useEffect

2.useEffect

Role: periodic function

useEffect involves three periodic function componentDidMount, componentDidUpdate, compinentWillUmount we look at a simple example

function App() {
  var [count, setCount] = useState(0);
  useEffect(() => {
    console.log(`update--${count}`);
  }, [count]);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Click</button>
    </div>
  );
}
Let's look at react hooks periodic function, how he works
function the App () { 
  the let [COUNT, setCount] = useState (0 ); 
  useEffect ( 
    () => {
       // default every time the rendering method need to be performed 
      the console.log ( 'didmount' )
       // To implement componentWillComponent, a return of the function to     
      return  function the unmount () { 
        the console.log ( 'the unmount' ) 
      } 
    } 
  ) 

  the let handleSetCount = useCallback (() => { 
    setCount ((preCount) => { 
      the let updatedCount = preCount +. 1 ;
       return  updatedCount ;
    } );
  })

  return <React.Fragment>
    {console.log('render')}
    <p>{`${count}`}</p>
    <button onClick={handleSetCount}>Click</button>
  </React.Fragment>
}

We can look at the execution cycle

The first time rendering execution render didmount

Click event execution order render unmount didmount

Easy to see that every time we will perform render rendered rendering, then removed the last useEffect, and then re-execute useEffect after rendering is complete

Such a default by a useEffec can perform two periodic functions, that is when we need to add some of the components required when the component was uninstalled that removed the function of time, this is very convenient, and so common is the setTimeout setIntrval timer

But after such a component rendering we would normally send a request to request data and then rewrite render this component, this will cause an infinite loop how to do, we can add a second option, after useEffect

Each time we perform to prevent useEffect

function the App () { 
  the let [COUNT, setCount] = useState (0 ); 
  useEffect ( 
    () => {
       // default every time the rendering method need to be performed 
      the console.log ( 'didmount' )
       // To implement componentWillComponent, a return of the function to     
      return  function the unmount () { 
        the console.log ( 'the unmount' ) 
      } 
    }, 
    [setCount] 
  ) 

  the let handleSetCount = useCallback (() => { 
    setCount ((preCount) => { 
      the let updatedCount = preCount + 1 ;
       return updatedCount;
    });
  })

  return <React.Fragment>
    {console.log('render')}
    <p>{`${count}`}</p>
    <button onClick={handleSetCount}>Click</button>
  </React.Fragment>
}

When passing the second parameter value does not become available when the function execution will skip useEffect

How to simulate componentDidMount and componentWillUmount, the second parameter we pass an empty array, this can be achieved only when the component was rendered with component uninstall execution time

function the App () { 
  the let [COUNT, setCount] = useState (0 ); 
  useEffect ( 
    () => {
       // default every time the rendering method need to be performed 
      the console.log ( 'didmount' )
       // To implement componentWillComponent, a return of the function to     
      return  function the unmount () { 
        the console.log ( 'the unmount' ) 
      } 
    }, 
    [] 
  ) 

  the let handleSetCount = useCallback (() => { 
    setCount ((preCount) => { 
      the let updatedCount = preCount +. 1 ;
       return updatedCount;
    });
  })

  return <React.Fragment>
    {console.log('render')}
    <p>{`${count}`}</p>
    <button onClick={handleSetCount}>Click</button>
  </React.Fragment>
}

However, this is a hidden problem: passing an empty array prone to problems. If we add a dependency, so it is easy to forget to add the item to which, if you miss a dependency, then the value will lapse at the next run useEffect, and may lead to some strange problems.

Common was that when we want to get to call sub-components when using the ref with the parent component, or we want to get the focus dom

function the App () { 
  the let [COUNT, setCount] = useState (0 ); 
  the let [value, the setValue] = useState ( '' ) 
  const inputRef = useRef (); 

  useEffect ( 
    () => {
       // the default rendering every all the method needs to perform 
      the console.log ( 'didmount' ) 

      // to implement componentWillComponent, the function to return a     
      return  function the unmount () { 
        the console.log ( 'the unmount' ) 
      } 
    }, 
    [inputRef] 
  ) 

  the let handleSetCount = useCallback (() => { 
    setCount ((preCount)=> {
      let updatedCount = preCount + 1;
      return updatedCount;
    });
  })

  let handleSetValue = function (e) {
    setValue(e.target.value);
  }

  return <React.Fragment>
    {console.log('render')}
    <p>{`${count}`}</p>
    <input
      ref={inputRef}
      value={value}
      onChange={handleSetValue}
    ></input>
    <button
      ref={inputRef}
      onClick={handleSetCount}
    >Click</button>

  </React.Fragment>
}

Now we realize a request instance

Request examples

function App() {
  let [data, setData] = useState(null);
  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(config);
      setData(result);
    };

    fetchData();
  }, []);

  return <div></div>;
}

Hook can be done by using separate interfaces

function useFetchHook(config, watch) {
  let [data, setData] = useState(null);
  let [status, setStatus] = useState(0);
  useEffect(
    () => {
      const fetchData = async () => {
        try {
          const result = await axios(config);
          setData(result);
          setStatus(0);
        } catch (e) {
          setStatus(1);
        }
        fetchData();
      };
    },
    watch ? [...watch] : []
  );

  return { data, status };
}

Now that we know the whole useState useEffect how to use, and our own to achieve a simple

Achieve useState

var val;
function useState(initVal) {
  let resultVal = val || initVal;
  function setVal(newVal) {
    resultVal = newVal;
    render();
  }
  return [resultVal, setVal]
}

Achieve useEffect

var watchArr = [];
function useEffect(fn, watch) {
  var hasWatchChange = true;
  hasWatchChange = watchArr && watch.every((val, i) => val === watchArr[i])
  if (hasWatchChange) {
    fn();
    watchArr = watch;
  }
}

hooks inside the two most commonly used API is useState and useEffect, now is not already know it, let's introduce some other API

3.useContext

Role: the component level to obtain content

Class components we used context, implementation class components

 
          
 const AppContext = React.createContext('target');
{React.Component the extends the App class 
  constructor (The props) { 
    Super (The props) 
  } 
  the render () { 
    return (
       <AppContext.Provider value = "Dark"> 
        <the Target /> 
      </AppContext.Provider>     ); 
  } 
} 
class the extends the Target {React.Component // subscribe static properties by defining the contextType // not defined is less than the acquired 
  static the contextType = the AppContext; 
  the render () { 
    the console.log ( the this .context);
     return <div> </ div>;
   } 
}


  
  

Hooks implementation

const AppContext = React.createContext('target');

function App() {
  useEffect(
    () => { },
    []
  );
  return <AppContext.Provider value="dark">
    <Target />
  </AppContext.Provider>;
}

function Target() {
  const value = useContext(AppContext);
  console.log(value);
  return <div></div>;
}

In the context of the need to subscribe to multiple times, it will better reflect the advantage of useContext.

Traditional implementations

function App() {
  return <CurrentUser.Consumer>
    {
      user => <Notifications.Consumer>
        {notifications =>
          <header>
            Welcome back, {user.name}!
              You have {notifications.length} notifications.
          </header>
        }
      </Notifications.Consumer>
    }
  </CurrentUser.Consumer>
}

hooks achieve

function App() {
  const user = useContext(CurrentUser);
  const notifications = useContext(Notifications);

  return (
    <header>
      Welcome back, {user.name}!
      You have {notifications.length} notifications.
    </header>
  );
}

Is not simply to be more than the traditional

4.useReducer

Role: complex state management, with essentially the same as the redux

Functional components if related to state management, we need the help of redux, then hooks need it, the answer is the same, simple state management we can be managed by useState, if more complex state management of it, react hook provided us methods useReducer

function init(initialCount) {
  return { count: initialCount };
}

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}

function Counter({ initialCount }) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({ type: 'reset', payload: initialCount })}>
        Reset
      </button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </>
  );
}

5.useCallback

Role: improve performance, cache events, reducing unnecessary rendering

When we created with class components, how would we do bind events

class App extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return <div>
      <p>{`hello~${name}`}</p>
      <button onClick={() => { console.log('click') }}>Click</button>
    </div>
  }
}

Write what will lead to results, that is, when will react when rendering think every event bindings are new, so new calculation

Improvements are as follows

class App extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log('click')
  }
  render() {
    return <div>
      <p>{`hello~${name}`}</p>
      <button onClick={this.handleClick}>Click</button>
    </div>
  }
}

We speak trigger function bound to this, this method to cache

hooks

function App() {
  let [count, setCount] = useState(0);
  return <div>
    <button onClick={() => setCount(1)} ></button>
  </div>
}

The same problem also exists so written, improvements are as follows

function App() {
  let [count, setCount] = useState(0);
  let handleSetCount = useCallback(() => {
    setCount(1);
  })
  return <div>
    <button onClick={handleSetCount} ></button>
  </div>
}

We come through the cache to optimize the effect of this event useCallback

6.useMemo

Action: improve the performance, rendering selective variation component

function App(target, target2) {
  const target = useMemo(() => {
    return <Target />
  }, [target])
  const target2 = useMemo(() => {
    return <Target2 />
  }, [target2])
  return <div>
    {target}
    {target2}
  </div>
}

When the target changes only render Target component, empathy and also the role of Target2 components

React.memo

Role: improve performance

If you want to achieve shouldComponentUpdate method class in it, except that it can only compare props, does not compare state:

const App = React.mome((target, target2) => {
  const target = useMemo(() => {
    return <Target />
  }, [target])
  const target2 = useMemo(() => {
    return <Target2 />
  }, [target2])
  return <div>
    {target}
    {target2}
  </div>
})

7.useRef

Role: Get dom dependencies

Class component implementation

class App extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  componentDidMount() {
    this.myRef.current.focus();
  }

  render() {
    return <input ref={this.myRef} type="text" />;
  }
}

hooks

function App() {
  let [value, setValue] = useState('')
  const inputRef = useRef();

  useEffect(
    () => {
    },
    [inputRef]
  )

  let handleSetValue = function (e) {
    setValue(e.target.value);
  }

  return <React.Fragment>
    <input
      ref={inputRef}
      value={value}
      onChange={handleSetValue}
    ></input>

  </React.Fragment>
}

Well, the basic use hooks on the introduction is over, now you understand how to hook up some of it ~

Code Address: https://github.com/Dqhan/React

 
 

 

 

 

Guess you like

Origin www.cnblogs.com/moran1992/p/12514899.html