含义:就是用组件包裹一层代理组件,在代理组件上,可以做一些,对源组件的强化操作。
代理props
function HOC(WrappedComponent){
const newProps = {name:'kevin'};
return props => <WrappedComponent {...props} {...newProps}/>
}
// 类组件
function HOC(WrappedComponent){
return class extends React.Component {
render(){
const newProps = {name:'kevin'};
return props => <WrappedComponent {...this.props} {...newProps}/>
}
}
}
function HOC(WrappedComponent){
return class extends React.Component {
constructor(props){
super(props);
this.state = {
name:'kevin'
}
this.onChange = this.onChange.bind(this)
}
onChange = (e)=>{
this.setState({
name:e.target.value
})
}
render(){
const newProps={
value:this.state.name,
onChange:this.onChange,
}
return <WrappedComponent {...this.props} {...newProps}/>
}
}
}
function HOC(WrappedComponent){
return props => (
<div>
{
props.isShow ? <WrappedComponent {...this.props} /> : <p>暂无数据展示</p>
}
</div>
)
}
function HOC(WrappedComponent){
return class extends React.Component {
render(){
const newProps = {name:'kevin'};
return props => (
<div style = {{width:'200px'}}>
<WrappedComponent {...this.props} {...newProps}/>
</div>
)
}
}
}
含义:继承传入的组件内容,即包装后的组件继承了原始组件本身,本质上是类的继承。
const HOC = WrappedComponent => {
return class extends WrappedComponent {
render(){
return super.render();
}
}
}
// 针对组件的生命周期进行处理
function HOC(WrappedComponent){
const didMount = WrappedComponent.prototype.componentDidMount;
return class extends WrappedComponent{
async componentDidMount(){
if(didMount){
await didMount.apply(this);
}
}
render(){
return super.render();
}
}
}
function HOC(WrappedComponent){
const didMount = WrappedComponent.prototype.componentDidMount;
const state = WrappedComponent.prototype.state;
return class extends WrappedComponent{
constructor(props){
super(props);
this.state = {
number:0
}
}
async componentDidMount(){
if(didMount){
await didMount.apply(this);
}
this.setState({
number:123,
...state,
})
}
render(){
return super.render();
}
}
}
const HOC = (WrappedComponent) => {
return class extends WrappedComponent {
render(){
if(this.props.isShow){
return super.render();
}else{
return <div>暂无数据</div>
}
}
}
}
const HOC = (WrappedComponent) => {
return class extends WrappedComponent {
render(){
const tree = super.render();
const newProps = {};
if(tree?.type === 'input'){
newProps.value = '开始自律';
}
const props = {
...tree.props,
...newProps,
}
return React.cloneElement(tree,props,tree.props.children)
}
}
}
代码复用
// import fetchMovieListByType from '.xxx';
// import MovieList from './components/xxxx';
class Comody extends React.Component {
state = {
movieList:[]
}
async componentDidMount(){
const movieList = await fetchMovieListByType("Comody");
this.setState({
movieList
})
}
render(){
return <MovieList data={this.data.movieList} emptyTips="empty Comody">
}
}
class Action extends React.Component {
state = {
movieList:[]
}
async componentDidMount(){
const movieList = await fetchMovieListByType("Action");
this.setState({
movieList
})
}
render(){
return <MovieList data={this.data.movieList} emptyTips="empty Action">
}
}
使用HOC
const withFetchimgHoc = (WrappedComponent,fetchingMethod,defaultProps) => {
return class extends React.Component {
async componentDidMount(){
const movieList = await fetchingMethod();
this.setState({
movieList
})
}
render(){
return <WrappedComponent data={this.data.movieList} {...defaultProps} {...this.props}>
}
}
}
withFetchimgHoc(MovieList,fetchMovieListByType("Action"),{emptyTips:'empty Action'})
withFetchimgHoc(MovieList,fetchMovieListByType("Comody"),{emptyTips:'empty Comody'})
组件渲染所耗费的时间
class Home extends React.component {
render(){
return <h1>Hello chongqing</h1>
}
}
function withTime(wrappedComponent){
let state,end;
return class extends wrappedComponent {
constructor(props){
super(props);
start = 0;
end = 0;
}
componentWillMount(){
super?.componentWillMount();
start = +Date.now()
}
componentDidMount(){
super?.componentDidMount();
end = +Date.now();
this.logger(`使用组件渲染时间:${end - start}ms`)
}
render(){
return super.render();
}
}
}
React Hooks: https://zh-hans.react.dev/reference/react
Hooks 用于函数式组件
const [state,setState] = useState(0);
// 模拟数据交互
function getUserInfo(a){
return new Promise((resolve) => {
setTimeout(()=>{
resolve({
name:a,
age:18,
})
},500)
})
}
const Demo = ({a}) => {
const [userMessage,setUserMessage] = useState({});
const [number,setNumber] = useState(0);
const div = useRef();
const handleResize = () =>{};
useEffect(() => {
getUserInfo(a).then(res => {
setUserMessage(res);
})
console.log(div.current);
window.addEventListener('resize',handleResize)
/**
* 只有当 props -> a 和 state -> number改变的时候,useEffect副作用函数重新执行
* 如果此时数组为空,证明函数只有在初始化的时候执行一次相当于componentDidMount
*/
},[a,number]) // 可以是 deep object
useEffect(()=> {
const timer = setInterval(()=>console.log(666),1000);
window.addEventListener('resize',handleResize);
// 此函数用于消除副作用 => 可以认为是退出组件的时候去执行
return function () {
clearInterval(timer);
window.removeEventListener('resize',handleResize)
}
},[a])
/*------useEffect 不能用于异步,即不能如下:------------*/
useEffect(async ()=>{
// 请求数据
const res = await getUserInfo(payload);
},[a,number])
useEffect(()=>{
// declare the async data fetching function
const fetchData = async()=>{
const data = await fetch('https://xxx.com');
const json = await data.json();
}
// call the function
const result = fetchData().then(console.error);
// ❌ 无效
setData(result);
},[])
/*------改进------------*/
useEffect(()=>{
const fetchData = async()=>{
const data = await fetch('https://xxx.com');
const json = await response.json();
setData(json);
}
// call the function
fetchData()
// make sure to catch any error
.catch(console.error)
},[])
// 或者
useEffect(()=>{
fetchData();
},[])
const fetchData = async()=>{}
return (
<div ref={div}>
<span>{userMessage.name}</sapn>
<span>{userMessage.age}</sapn>
<div onClick={()=>setNumber(2)}>{number}</div>
</div>
)
}
作用:获取真实元素DOM标签的方式
const DemoUseRef = () => {
const dom = useRef(null);
const handleSubmit = () => {
console.log(dom.current)
}
return (
<div>
<div ref={dom}>div</div>
</div>
)
}
// 只想存储一个值,而不触发页面的渲染、视图的更新 => 变量更新
const currentRef = useRef(1);
currentRef.current = 2;
作用:类似于从全局中管控一个上下文的状态
/* 用useContext方式*/
const DemoContext = () => {
const value = useContext(Context);
return <div>my name is {value.name}</div>
}
/* 用Context.Consumer方式 */
const DemoContext1 = () => {
return (
<Context.Consumer>
{(value) => <div>my name is {value.name}</div>}
</Context.Consumer>
)
}
export default () => {
return (
<div>
<Context.Provider value = {{name:' 二娃'}}>
<DemoContext/>
<DemoContext1/>
</Context.Provider>
</div>
)
}
const DemoUseReducer = () => {
/* number为更新后的state值,dispatchNumber 为当前的派发函数*/
const[number,dispatchNumber] = useReducer((state,action) => {
const {payload,name} = action;
/*return 的值为新的state*/
switch(name){
case 'a':
return state + 1;
case 'b':
return state - 1;
case 'c':
return payload;
}
return state;
},0);
return (
<div>
当前值{number}
{/*派发更新*/}
<button onClick={() =>dispatchNumber({name:'a'})}>增加</button>
<button onClick={() =>dispatchNumber({name:'b'})}>减少</button>
<button onClick={() =>dispatchNumber({name:'c',payload:888})}>赋值</button>
{/*把dispatch 和state传递给子组件*/}
<MyChildren dispatch={dispatchNumber} State={{number}}/>
<Context.Provider value = {{dispatchNumber , number}}>
</Context.Provider>
</div>
)
}
进行性能优化
useMemo(()=>{
<div>
list.map(i => (
<span>{i.xxx}</span>
))
},[list])
强调的是一种函数式编程的思维
const [] = useXXX();
import {useEffect} from 'react';
const useTitle = (title) => {
useEffect(() => {
document.title = title;
},[]);
}
export default useTitle
// 在别的react组件这样去调用
import useTitle from './xxx';
const App = () => {
useTitle("1243");
return <div>234</div>
}