ReactHook Quick Boarding

React16.8 started with 10 Hook s built in, with two cores:

  • State Management: useState
  • Side effects management: useEffect

Stateful functions

useState

Stateful Component Writing:

class Example extends React.Component {
	constructor(props) {
      super(props);
      this.state = {
        count: 0
      };
    }
    render() {
      return (
        <div>
          <p>You clicked {this.state.count} times</p>
          <button onClick={() => this.setState({ count: this.state.count + 1 })}>
            Click me
          </button>
        </div>
      );
    }
}

Stateless Component Writing:

const Example = props => {
  const { count, onClick } = props;
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={onClick}>
        Click me
      </button>
    </div>
  )
}

hooks are stateful functions:

import { useState } from 'react';
const Example = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
        <p>You clicked {count} times</p>
        <button onClick={() => setCount(count + 1)}>
          Click me
        </button>
    </div>
  )
}

Note that setter s generated by useState do not merge when updating the state:

const [data, setData] = useState({ count: 0, name: 'abc' });   // name is not used and should be declared separately
useEffect(() => {
  // data: { count: 0, name: 'abc' } -> { count: 0 }
  setData({ count: 1 })
})

In our pure function components, each useState produces a pair of States and stateSetter s. We don't need to consider more state tree designs and component partitioning designs. Logical code can be written directly from the root component.

The development path we apply is roughly divided into the following three stages, and hook-based development will be more flexible:

  • Pre farm: The vast majority of cases can be handled simply by combining related states into several independent state variables
  • Mid-term gank: As the state of a component gradually increases, it is easy to leave updates to reducer to manage
  • Later regiment battle: When more states and more complex logic of states are involved, we can solve problems by pulling complicated state logic codes out of custom hook s at almost zero cost

Highly flexible redux, pure no dependency

Unlike true redux, hook offers a more flexible and pure pattern in practice.Now we can implement a global Redux with 10 lines of code or a local Redux with 2 lines of code anywhere and anytime:

10 lines of code implement a global redux:

import React from 'react';
const store = React.createContext(null);
export const initialState = { name: 'aa' };
export function reducer(state, action) {
  switch (action.type) {
    case 'changeName': return { ...state, name: action.payload };
    default: throw new Error('Unexpected action');
  }
}
export default store;

Provider root component hangs:

import React, { useReducer } from 'react';
import store, { reducer, initialState } from './store';

function App() {
	const [state, dispatch] = useReducer(reducer, initialState);
    return (
    	<store.Provider value={{ state, dispatch }}>
      		<div />
      	</store>
    )
}

Subcomponent calls:

import React, { useContext } from 'react';
import store from './store';

function Child() {
	const { state, dispatch } = useContext(store);
}

A local redux anywhere:

import React, { useReducer } from 'react';
const initialState = { name: 'aa' };
function reducer(state, action) {
	switch (action.type) {
      case 'changeName': return { ...state, name: action.payload };
      default: throw new Error('Unexpected action');
    }
}

function Component() {
	const [state, dispatch] = useReducer(reducer, initialState);
  	...
}

Custom hook

When we want to share logic between two functions, we extract it into the third function.Components and hooks are functions, so the same applies.The difference is that a hook is a stateful function that enables a higher level of reuse than previously possible with pure functions - the reuse of state logic.

Compoonent writing:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      name: undefined
    };
  }
  componentDidMount() {
    service.getInitialCount().then(data => {
      this.setState({ count: data });
    });
    service.getInitialName().then(data => {
      this.setState({ name: data });
    });
  }
  componentWillUnmount() {
    service.finishCounting().then(() => {
      alert('Count Complete');
    });
  }
  addCount = () => {
    this.setState({ count: this.state.count + 1 });
  };
  handleNameChange = name => {
    this.setState({ name });
  };
  render() {
    const { count, name } = this.state;
    return (
      <div>
        <div>
          <p>You clicked {count} times</p>
          <button onClick={this.addCount}>Click me</button>
        </div>
        <Input value={name} onChange={this.handleNameChange} />
      </div>
    );
  }
}

hook notation:

function useCount(initialValue) {
  const [count, setCount] = useState(initialValue);
  useEffect(() => {
    service.getInitialCount().then(data => {
      setCount(data);
    });
    return () => {
      service.finishCounting().then(() => {
        alert('Count Complete');
      });
    };
  }, []);
  function addCount() {
    setCount(c => c + 1);
  }
  return { count, addCount };
}
function useName(initialValue) {
  const [name, setName] = useState(initialValue);
  useEffect(() => {
    service.getInitialName().then(data => {
      setName(data);
    });
  }, []);
  function handleNameChange(value) {
    setName(value);
  }
  return { name, handleNameChange };
}
const App = () => {
  const { count, addCount } = useCount(0);
  const { name, setName } = useName();
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={addCount}>Click me</button>
      <Input value={name} onChange={setName} />
    </div>
  );
};

As mentioned above, in the writing of component, count and name, along with the ticket logic associated with them, are scattered throughout the life cycle and methods of a component.Although we can extract the States and change action s of a component into a common one, the side effects involved ultimately do not get around the component's life cycle.However, there is only one life cycle for a component, and it is inevitable that some entirely irrelevant logic will be written together.Thus, complete state logic reuse cannot be achieved.

Let's look again at the use of hooks, where we encapsulate count-related logic and name-related logic in separate, enclosed logical units through custom hooks.The lifecycle of the previous class component no longer exists here.Lifecycle is a concept that is strongly coupled with UI and, while easy to understand, is naturally far away from data.Hooks encapsulate components side-effects with a data stream subscription similar to rxjs mode, which has the advantage that we only need to care about the data.So hooks do more than simplify the definition and packaging of state s.

Custom hooks separate state logic from UI and enable very high-level Abstract reuse of business logic by reasonably abstracting custom hooks

hook principle

let hooks, i;
function useState() {
  i++;
  if (hooks[i]) {
    // When rendering again
    return hooks[i];
  }
  // First Rendering
  hooks.push(...);
}
// Preparing to render
i = -1;
hooks = fiber.hooks || [];
// Invoke Component
Component();
// Cache the status of Hooks
fiber.hooks = hooks;

This article is published by blog OpenWrite Release!

Keywords: Javascript React

Added by silverphpd on Mon, 25 May 2020 19:53:17 +0300