Hooks
My React Learning Note (5) 
Topic: Hooks 
useSelector, useDispatch 
useSelector , useDispatch 是两个 react-redux 提供的hooks,这样就不需要 mapStateToProps
和 mapDispatchToProps
useState 
https://github.com/ZhangMYihua/use-state-example 
const  [name, setName] = useState('Haha' )() =>  setName("Wahaha" )}>Set  Name to Wahaha </button>
useEffect 
a function gets called whenever the update lifecycle method (re-render) is fired
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 userEffect(()=> {console .log('hello' )()=> {console .log('hello' )()=> {console .log('hello' )
use Async function in useEffect
1 2 3 4 5 6 7 8 useEffect(()=> {const  fetchFunc = async  () =>{const  response = await  fetch(`https://.....` )const  resJson = await  response.json()0 ])
The code above will cause an infinite loop between:
setUser (update DOM) -> useEffect -> setUser -> useEffect…
1 2 3 4 5 6 7 8 9 ()=> {const  fetchFunc = async  () =>{const  response = await  fetch(`https://.....` )const  resJson = await  response.json()0 ])
If we want condition, we put them into useEffect 
Class-based component to Function-based component 
Some thing we changed from class-based components to function-based components:
this.state -> useState
 
this.props
We destructure props we want from the input params of the function component
 
 
1 2 3 4 5 6 7 8 9 const  SignIn = ({ emailSignInStart, googleSignInStart } ) =>  {const  [userCredentials, setUserCredentials] = useState({"" ,"" ,return  (...)
注意,如果当我们把多个 state values 变成一个 object 然后一起更新时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const  [userCredentials, setUserCredentials] = useState({"" ,"" ,"" ,"" ,const  { displayName, email, password, confirmPassword } = userCredentials;  const  handleChange = (event ) =>  {console .log("here" );console .log(event.target);const  { name, value } = event.target;
One component will re-render only in three conditions:
Props change 
setState from useStateparent re-render 
 
userEffect -> Unmount 
1 2 3 4 5 6 7 useEffect(() =>  {return  () =>  {
1 2 3 4 5 6 7 8 9 10 11 12 13 useEffect(() =>  {console .log("I am subscribing" );const  unsubscribeFromCollection = firestore"collections" )(snapshot ) =>  console .log(snapshot));return  () =>  {console .log("I am unsubscribing!" );
useEffect Cheat Sheet 
A quick recap of what we have learned about useEffect:
ComponentDidMount 
1 2 3 4 5 6 7 8 9 componentDidMount (console .log('I just mounted!' );() =>  {console .log('I just mounted!' );
ComponentWillUnmount 
1 2 3 4 5 6 7 8 9 componentWillUnmount (console .log('I am unmounting' );() =>  {return  () =>  console .log('I am unmounting' );
ComponentWillReceiveProps 
1 2 3 4 5 6 7 8 9 10 11 componentWillReceiveProps (nextProps )if  (nextProps.count !== this .props.count) {console .log('count changed' , nextProps.count);() =>  {console .log('count changed' , props.count);
Custom Hook 
https://github.com/ZhangMYihua/custom-hook-example 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import  { useState, useEffect } from  'react' ;const  useFetch = url  =>const  [data, setData] = useState(null );() =>  {const  fetchData = async  () => {const  res = await  fetch(url);const  dataArray = await  res.json();0 ]);return  data;export  default  useFetch;
useReducer 
https://github.com/ZhangMYihua/useReducer-example 
https://reactjs.org/docs/hooks-reference.html#usereducer 
https://react-redux.js.org/api/hooks 
React-Redux Hook 
useSelector, useDispatch 
useSelector: Allows you to extract data from the Redux store state, using a selector function.
The selector is approximately equivalent to the mapStateToProps argument to connect
useSelector() will also subscribe to the Redux store, and run your selector whenever an action is dispatched.
 
useDispatch: This hook returns a reference to the dispatch function from the Redux store. You may use it to dispatch actions as needed.
 
selector itself is a function receives state object
useSelector receives a selector that returns some state, and useSelector will ensure to up-to-date with the state.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const  App = () =>  {const  currentUser = useSelector(selectCurrentUser);const  dispatch = useDispatch();() =>  {return  (...)
Adavanced useState, useEffect 
When a functional component gets re-rendered, do it from top to bottom in synchronous manner.
A component is re-rendered if
Props change 
State change 
parent re-render 
 
We can pass in a function into useState
1 setCount((prev ) =>  prev+1 )
If a function is dependent on a state, we shall put that function into useEffect. If not, we can place it out of component so it only renders once.
useCallback 
If a function depends on a state but is outside of useEffect We cannot know its dependency from looking at the code.
we can use useEffect to preserve function outside of useEffect and know its dependency
1 2 3 4 5 6 7 const  myFunc = useCallback(()=> {console .log('effect on'  + test1)()=> {
useMemo 
1 2 3 4 5 6 7 cosnt myObj = {'my value of a is ' + test1()=> {console .log(myObj.a)
This will always be re-rendered every single time regardless of whether myObj changed or not
(reference comparison, a new object is initialize every single time for the functional component re-rendering)
1 2 3 4 5 6 7 cosnt myObj = useMemo(() =>  ({'my value of a is ' + test1()=> {console .log(myObj.a)
useMemo and useCallback can be very helpful when you want some behavior to be performed based on a specific object or function 
useLayoutEffect 
useEffect runs after the paint of the component
useLayoutEffect runs before the paint of the component
useContext 
Component way of using context (replacing Redux)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import  React from  "react" ;import  { connect } from  "react-redux" ;import  CollectionItem from  "../../components/collection-item/collection-item.component" ;import  { selectCollection } from  "../../redux/shop/shop.selectors" ;import  "./collection.styles.scss" ;import  CollectionsContext from  "../../contexts/collections/collections.context" ;const  CollectionPage = ({ match } ) =>  {return  ((collections ) =>  {const  collection = collections[match.params.collectionId];const  { title, items } = collection;return  ("collection-page" >"title" >{title}</h2>"items" >(item ) =>  (const  mapStateToProps = (state, ownProps ) =>  ({export  default  CollectionPage;
useContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import  React, { useContext } from  "react" ;import  { connect } from  "react-redux" ;import  CollectionItem from  "../../components/collection-item/collection-item.component" ;import  { selectCollection } from  "../../redux/shop/shop.selectors" ;import  "./collection.styles.scss" ;import  CollectionsContext from  "../../contexts/collections/collections.context" ;const  CollectionPage = ({ match } ) =>  {const  collections = useContext(CollectionsContext);const  { title, items } = collections[match.params.collectionId];return  ("collection-page" >"title" >{title}</h2>"items" >(item ) =>  (export  default  CollectionPage;
However, useContext is not very handy when we need to update a state.  The problem it solves is to easily pass a state of a high node in the DOM tree easily to the lower state.
An example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import  React, { createContext, useContext, useEffect, useState } from  "react" ;import  { addItemToCart, removeItemFromCart } from  "./cart.utils" ;export  const  CartContext = createContext({true ,() =>  {},() =>  {},() =>  {},() =>  {},0 ,const  CartProvider = ({ children } ) =>  {const  [cartItems, setCartItems] = useState([]);const  [cartItemsCount, setCartItemsCount] = useState(0 );const  [hidden, setHidden] = useState(true );const  toggleHidden = () =>  setHidden(!hidden);const  addItem = (item ) =>  setCartItems(addItemToCart(cartItems, item));return  (export  default  CartProvider;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import  React from  "react" ;import  ReactDOM from  "react-dom" ;import  { BrowserRouter } from  "react-router-dom" ;import  { Provider } from  "react-redux" ;import  { PersistGate } from  "redux-persist/integration/react" ;import  { store, persistor } from  "./redux/store" ;import  CartProvider from  "./providers/cart/cart.provider" ;import  "./index.css" ;import  App from  "./App" ;document .getElementById("root" )
具体实现看下面的代码, 非常有帮助!
Very helpful!
Code below:
https://github.com/ZhangMYihua/react-context-practice 
https://github.com/ZhangMYihua/react-context-complete