clone 属性
!!响应式字体大小 
[cc lang=”js”]const theme = createMuiTheme();
theme.typography.h1 = { 
  fontSize: ‘3rem’, 
  ‘@media (min-width:600px)’: { 
    fontSize: ‘4.5rem’, 
  }, 
  [theme.breakpoints.up(‘md’)]: { 
    fontSize: ‘6rem’, 
  }, 
};[/cc]
自定义变量 
[cc lang=”js”]
import Checkbox from ‘@material-ui/core/Checkbox’; 
import { createMuiTheme, withStyles } from ‘@material-ui/core/styles’; 
import { ThemeProvider } from ‘@material-ui/styles’; 
import { orange } from ‘@material-ui/core/colors’;
const styles = theme => ({ 
  root: { 
    color: theme.status.danger, 
    ‘&$checked’: { 
      color: theme.status.danger, 
    }, 
  }, 
  checked: {}, 
});
let CustomCheckbox = props => ( 
   
);
CustomCheckbox.propTypes = { 
  classes: PropTypes.object.isRequired, 
};
CustomCheckbox = withStyles(styles)(CustomCheckbox);
const theme = createMuiTheme({ 
  status: { 
    // My business variables 
    danger: orange[500], 
  }, 
});
function CustomStyles() { 
  return ( 
     
       
     
  ); 
}
export default CustomStyles;[/cc]
**************** 
每个 material-ui 组件都有一个 class 类, theme 可以从写这个类,类的样式可以到组件详情里看到 
当配置变量不够强大的时候,您可以使用theme的overrides来让Material-UI隐式地为您注入样式规则。 这是一个非常强大的特性。
[cc lang=”js”]const theme = createMuiTheme({ 
  overrides: { 
    // Style sheet name ⚛️ 
    MuiButton: { 
      // Name of the rule 
      text: { 
        // Some CSS 
        color: ‘white’, 
      }, 
    }, 
  }, 
});[/cc] 
**************
         
    
        
    
 
        
    
        
    
    Add the following to src/components/AsyncComponent.js. 
高级组件
[cc lang=”javascript”] 
import React, { Component } from “react”;
export default function asyncComponent(importComponent) { 
  class AsyncComponent extends Component { 
    constructor(props) { 
      super(props);
      this.state = { 
        component: null 
      }; 
    }
    async componentDidMount() { 
      const { default: component } = await importComponent();
      this.setState({ 
        component: component 
      }); 
    }
    render() { 
      const C = this.state.component;
      return C ?   : null; 
    } 
  }
  return AsyncComponent; 
}[/cc]
Use it
[cc lang=”javascript”]const AsyncHome = asyncComponent(() => import(“./containers/Home”));[/cc]
in your rooter 
[cc lang=”javascript”] 
import React from “react”; 
import { Route, Switch } from “react-router-dom”; 
import asyncComponent from “./components/AsyncComponent”; 
import AppliedRoute from “./components/AppliedRoute”; 
import AuthenticatedRoute from “./components/AuthenticatedRoute”; 
import UnauthenticatedRoute from “./components/UnauthenticatedRoute”;
const AsyncHome = asyncComponent(() => import(“./containers/Home”)); 
const AsyncLogin = asyncComponent(() => import(“./containers/Login”)); 
const AsyncNotes = asyncComponent(() => import(“./containers/Notes”)); 
const AsyncSignup = asyncComponent(() => import(“./containers/Signup”)); 
const AsyncNewNote = asyncComponent(() => import(“./containers/NewNote”)); 
const AsyncNotFound = asyncComponent(() => import(“./containers/NotFound”));
export default ({ childProps }) => 
   
     
     
     
     
     
    {/* Finally, catch all unmatched routes */} 
     
   
;[/cc]
可以用 react-loadable 代替 
[cc lang=”javascript”]const AsyncHome = Loadable({ 
  loader: () => import(“./containers/Home”), 
  loading: MyLoadingComponent 
});
const MyLoadingComponent = ({isLoading, error}) => { 
  // Handle the loading state 
  if (isLoading) { 
    return 
Loading…
; 
  } 
  // Handle the error state 
  else if (error) { 
    return 
Sorry, there was a problem loading the page.
; 
  } 
  else { 
    return null; 
  } 
};[/cc]
         
    
        
    
 
        
    
        
    
    react 复用 render Props 、 High order component 和 Hook 
[cc lang=”js”]// render props 
class Mouse Tracker extends React.Component { 
  render ( ) { 
    return ( 
       < div > 
         < h1 > 移动鼠标! </ h1 > 
        < Mouse render = { mouse  => ( 
		// Mouse 组件内 props.render(mouse) , Mouse 组件为props.render函数提供 mouse 坐标参数,渲染内容为render组件内容 
           
        ) } /> 
		// render 函数因为是一个函数直接量, 更新时每次都是不同的, 可以定义一个函数变量
      
 
     ) ; 
   } 
 } [/cc]
React Hook  
[cc lang=”js”]
componentDidMount() { 
	ChatAPI.subscribeToFriendStatus( 
		this.props.friend.id, 
		this.handleStatusChange 
	); 
}
componentWillUnmount() { 
	ChatAPI.unsubscribeFromFriendStatus( 
		this.props.friend.id, 
		this.handleStatusChange 
	); 
}
// 如果 props.friend 发生变化,这将导致订阅不能取消, 从而导致内存泄露或崩溃的问题 
// useEffect 增加didUpdate,解决了 class 组件中因为没有处理更新逻辑而导致常见的 bug 
useEffect(() => { 
	// … 
	ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); 
	return () => { 
		ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); 
	}; 
}); 
react hook 解决更新中重新订阅,并删除上一次订阅 
[/cc]
!! 通过跳过 Effect 进行性能优化 
prevProps 或 prevState 
[cc lang=”js”] 
componentDidUpdate(prevProps, prevState) { 
	if (prevState.count !== this.state.count) { 
		document.title = `You clicked ${this.state.count} times`; 
	} 
}[/cc] 
Effect 加入第二个参数 
[cc] 
useEffect(() => { 
document.title = `You clicked ${count} times`; 
}, [count]); // 仅在 count 更改时更新[/cc]
!!Effect 第二个参数 
// 依赖列表中省略函数 
!!如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组 []
1 如果函数里没有用到 props 或state, 第二个参数可以是 [], 这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行 
2. 如果函数里用到了, 第二个参数 需要加入 [someProp]
 3. setState 的函数式更新形式   解决性能问题,
*******关注点分离 创建多个 effect 干不同的事 
[cc lang=”js”] 
function FriendStatusWithCounter(props) { 
  const [count, setCount] = useState(0); 
  useEffect(() => { 
    document.title = `You clicked ${count} times`; 
  });
  const [isOnline, setIsOnline] = useState(null); 
  useEffect(() => { 
    function handleStatusChange(status) { 
      setIsOnline(status.isOnline); 
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); 
    return () => { 
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); 
    }; 
  }); 
  // … 
}[/cc]
**************只在最顶层使用 Hook 
不要在循环,条件或嵌套函数中调用 Hook
*********自定义hook 
[cc lang=”js”] 
import React, { useState, useEffect } from ‘react’;
function useFriendStatus(friendID) { 
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => { 
    function handleStatusChange(status) { 
      setIsOnline(status.isOnline); 
    }
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); 
    return () => { 
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); 
    }; 
  });
  return isOnline; 
}
// 使用 hook 
function FriendListItem(props) { 
  const isOnline = useFriendStatus(props.friend.id);
  return (
      {props.friend.name}
     
  ); 
}[/cc]
******要点 
1 函数式的 setState 结合展开运算符来达到合并更新对象的效果 
[cc lang=”js”]setState(prevState => { 
  // 也可以使用 Object.assign 
  return {…prevState, …updatedValues}; 
});[/cc]
2 effect 
 * effect 的依赖发生变化,它就会被重新创建 
 * 请记得 React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect,因此会使得处理额外操作很方便 
 * 要记住 effect 外部的函数使用了哪些 props 和 state 很难。这也是为什么 通常你会想要在 effect 内部 去声明它所需要的函数。 这样就能容易的看出那个 effect 依赖了组件作用域中的哪些值 
 * 可以通过effect 内部声明变量, 并返回修改变量的函数, 例如组件已经卸载 但请求还在继续,清除卸载hook时设置变量,让状态不更新 
 [cc lang=”js”]useEffect(() => { 
    let ignore = false; 
    async function fetchProduct() { 
      const response = await fetch(‘http://myapi/product/’ + productId); 
      const json = await response.json(); 
      if (!ignore) setProduct(json); 
    }
    fetchProduct(); 
    return () => { ignore = true }; 
  }, [productId]);[/cc]
 ***** 你可以把函数加入 effect 的依赖, 但把它的定义包裹进useCallback Hook。这就确保了它不随渲染而改变,除非 它自身 的依赖发生了改变 
[cc lang=”js”]  function ProductPage({ productId }) { 
  // ✅ 用 useCallback 包裹以避免随渲染发生改变 
  const fetchProduct = useCallback(() => { 
    // … Does something with productId … 
  }, [productId]); // ✅ useCallback 的所有依赖都被指定了
  return  ; 
}
function ProductDetails({ fetchProduct }) { 
  useEffect(() => { 
    fetchProduct(); 
  }, [fetchProduct]); // ✅ useEffect 的所有依赖都被指定了 
  // … 
}[/cc]
***** 如果我的 effect 的依赖频繁变化,我该怎么办 
[cc lang=”js”]function Counter() { 
  const [count, setCount] = useState(0);
  useEffect(() => { 
    const id = setInterval(() => { 
      setCount(count + 1); // 这个 effect 依赖于 `count` state 
    }, 1000); 
    return () => clearInterval(id); 
  }, []); // ? Bug: `count` 没有被指定为依赖 // 如果指定count 依赖,effect 改变count,effect就会重新执行,死循环
  return 
{count} 
; 
  } 
  // setState 的函数式更新形式 ,它允许我们指定 state 该 如何 改变而不用引用 当前 state 
  function Counter() { 
  const [count, setCount] = useState(0);
  useEffect(() => { 
    const id = setInterval(() => { 
      setCount(c => c + 1); // ✅ 在这不依赖于外部的 `count` 变量 
    }, 1000); 
    return () => clearInterval(id); 
  }, []); // ✅ 我们的 effect 不适用组件作用域中的任何变量
  return 
{count} 
; 
} 
  [/cc]
 3 useReduce
 你可以选择惰性地创建初始 state。为此,需要将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialArg) 
[cc lang=”js”] 
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); //重置 state 的 action 做处理提供了便利 
    default: 
      throw new Error(); 
  } 
}
function Counter({initialCount}) { 
  const [state, dispatch] = useReducer(reducer, initialCount, init); 
  return ( 
    <> 
      Count: {state.count} 
       dispatch({type: ‘reset’, payload: initialCount})}> 
        Reset 
       
       dispatch({type: ‘decrement’})}>-  
       dispatch({type: ‘increment’})}>+  
    > 
  ); 
}[/cc]
4.useCallback 
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新 
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。 
[cc lang=”js”]const memoizedCallback = useCallback( 
  () => { 
    doSomething(a, b); 
  }, 
  [a, b], 
);[/cc]
5.useMemo 
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。 
记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。 
[cc lang=”js”]const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);[/cc]
6. useRef 
[cc lang=”js”] 
function TextInputWithFocusButton() { 
  const inputEl = useRef(null); 
  const onButtonClick = () => { 
    // `current` 指向已挂载到 DOM 上的文本输入元素 
    inputEl.current.focus(); 
  }; 
  return ( 
    <> 
       
      Focus the input  
    > 
  ); 
}[/cc] 
请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现 ref