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> ); }
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
{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