*【需要升入理解】React deeper into Compo

2020-05-25  本文已影响0人  33jubi

这里涉及很多去优化app的内容,在实践不足的情况下理解会比较局限,最好可以在反复实践过程中回头理解和尝试优化自己的程序。

A better project structure

import React from 'react'
import Person
const persons(props)=>props.persons.map((person,index)=>{
        return<Person
          click = {()=>this.clicked(index)}
          name = {person.name}
          age = {person.age}
          key = {person.id}
          changed={(event)=>this.changed(event,person)}
        />
        })
...
import Persons
<Persons 
  persons = {this.state.persons}
  clicked = {this.deletePersonHandler}
  changed = {this.nameChangedHandler}/>

stateless component VS stateful component

stateless component :functional component without state hoc
stateful component: class component & functional component with state hoc
stateless:presentational componet
=>

Class based component VS functional Component
Jietu20200523-211717.jpg

functional component =>props.xxx不需要this

Class component Lifecycle

constructor()
getDerivedStateFromProps()?
getSnapshotBeforeUpdate()?
componentDidCatch()
componentWillUnmount().
shouldComponentUpdate()?
componentDidUpdate()
componentDidMount()
render()

Component Lifecycle--Creation
Component Lifecycle--Update
using useEffect() in functional components

1.useEffect(()=>{...//Http requests}) 当render该组件时会跑一遍(其他组件rerender带动该组件render也会跑一遍
2.useEffect(()=>{...//Http requests},[props.persons]) 当persons改变时就会跑一遍
3.useEffect(()=>{...//Http requests},[]) 任何props改变都会跑一遍

import React,{useEffect} from 'react'

const cockpit = (props)=>{
  useEffect(()=>{
    //Http requests
    
  },[props.persons])//当persons改变时就会跑一遍
}
Cleaning up with Lifecycle Hooks & useEffect() 组件有显示状态和不显示状态,不显示时其中的一些方法就需要‘clean up’[lifecycle hooks 和react hooks无关]

在useEffect里加return一个arrow function

const cockpit  = props =>{
  useEffect(()=>{
    //...
    const timer = setTimeout(()=>{
      alert('Saved data to cloud');
    },1000);
    return()=>{
      clearTimeout(timer);
      console.log([cockpit.js] cleanup work in useEffect');
    }
  },[])
}
优化 Using shouldComponentUpdate() for Optimization
shouldComponentUpdate(nextProps,nextState){
  if(nextProps.persons !== this.props.persons){
    return true;//update(rerendering)
  }else{
    return flase;
  }
}

Note

componentDidUpdate() will not be invoked if shouldComponentUpdate() returns false.

this.propsnextProps和进行比较this.statenextState然后返回false以告知React可以跳过更新。请注意,返回false并不能防止子组件在状态更改时重新呈现。
目前,如果shouldComponentUpdate()回报false,然后UNSAFE_componentWillUpdate()render()componentDidUpdate()将不会被调用。将来,React可能会被shouldComponentUpdate()视为提示而不是严格的指令,并且返回false可能仍会导致组件的重新渲染。

Optimizing Fuctional Components with React.memo() [componentDidUpdate() in functional component]
export default React.memo(cockpit);
PureComponents instead of shouldComponentUpdate()
//只有当相关变量update才render
shouldComponentUpdate(nextProps,nextState){
  if(
      nextProps.persons !== this.props.persons ||
      nextProps.changed !== this.props.changed ||
      nextProps.clicked !== this.props.clicked
   ){
     return true;
   } else {
     return false;
   }
}

替代
实现和前面 shouldComponentUpdate()想做的目标=》和子组件无关的即使父组件rerender也不会直接导致子组件rerender

import React,{PureComponent} from 'react';

class Persons extends PureComponent{

}
How React Updates The Real DOM
Jietu20200525-163011.jpg
Rendering Adjacent JSX Elements

1.<></>
2.[<p key=‘i1’/>,<div key=‘i2’/>]
3.Aux:(higher order component-hoc)
4.React.Fragment<React.Fragment></React.Fragment>

//Aux.js
import React from ' react';
export default const aux = props=>props.chilren;
<Aux>
   ...
</Aux>

...解释
JSX:

import React from 'react';

const heading = props => (

  <h1>{props.title}</h1>

  <h2>{props.subtitle}</h2>

);

export default heading;

This is NOT allowed because it would be translated to:


import React from 'react';

const heading = props => React.createElement('h1', {},

props.title) React.createElement('h2', {}, props.subtitle);

export default heading;

This is invalid JavaScript syntax, you’re trying to return two expressions (two React.createElement() calls).
You are allowed to do that if you
a) return an array of React.createElement() calls OR
b) return a single React.createElement() call that wraps the other two

a)

import React from 'react';
const heading = props => [
  React.createElement('h1', {key: 'i1'}, props.title),
  React.createElement('h2', {key: 'i2'}, props.subtitle)
];
export default heading;

This is equivalent to returning an array of keyed JSX elements.
b)

import React from 'react';
import Aux from '../hoc/Aux';
const heading = props => React.createElement(
Aux,
{},
React.createElement('h1', {key: 'i1'}, props.title),
React.createElement('h2', {key: 'i2'}, props.subtitle)
);
export default heading;

This is equivalent to using <Aux>.
b) works because we can pass as many children (third argument to React.createElement()) as we want.

Higher Order Components(HOC) intro
//WithClass.js
import React from 'react';
export default const withClass = props=>(
  <div className={props.classes}>{props.children}</div>
)



//App.js
...
return(
  <WithClass classes={classes.App}>
    ...
  </WithClass>
)
//withClass.js
import React from 'react';
export default const withClass = (WrappedComponent, className)=>(
  return props=>(<div className={className}><WrappedComponent/></div>)
)



//App.js
...
return(
  ...
)
export default withClass(App,classes.App);
Passing unkonwn props
//withClass.js
import React from 'react';
export default const withClass = (WrappedComponent, className)=>(
  return props=>(<div className={className}>
    <WrappedComponent {...props}/>
  </div>)
)
Setting state correctly
Using Prop Types

npm install --save prop-types

import PropTypes from 'prp-types';

class Person extends Component{
  ......
}

Person.propTypes = {
  click: PropTypes.func,
  name:PropTypes.string,
  age:PropTypes.number,
  changed: PropTypes.func
}
Using Refs
componentDidMount(){
  this.inputElement.focus();
}
...
<input 
  ref={(inputEl)=>{this.inputElement = inputEl}}/>
constructor(props){
  super(props);
  this.inputElement.current.focus();
  
}
...
<input 
  ref={this.inputElement}/>
Refs With React Hooks
import React,{useRef,useEffect} from 'react'
const cockpit = props =>{
  const toogleBtnRef = useRef(null);
  
  useEffect(){
  //理解运行周期(顺序),functional component Ref只能在useEffect中进行操作(因为useEffect是在return后run的)
    toogleBtnRef.current.focus();
  }
  ...
  return(
  <button ref={toogleBtnRef}/>
  )
}
Understanding Prop Chain Problems
Using the Context API
//auth-context.js

import React from 'react';

const authContext = React.createContext({authenticated: false,login()=>{}});

export default authContext;
...
//App.js
import AuthContext from '...'
<AuthContext.Provider value={authenticated:this.state.authenticated,login:this.loginHandler}>
  <Cockpit .../>//不用再传login方法
  {person}
</AuthContext.Provider>



//person.js
import AuthContext from '...'
return(
<AuthContext.Consumer >
 {(context)=>{
    context.authenticated?<p>true</p>:<p>false</p>
 }}
</AuthContext.Consumer>
)



//cockpit.js
return(
<AuthContext.Consumer >
 {(context)=>{
     <button onClick={context.login}>Log in</button>
 }}
</AuthContext.Consumer>
)
contextType & useContext()
import AuthContext from '...'
static contexType = Authontext;

componentDidMount(){
  var a = this.context.Authontext
}
return(...{this.context.Authontext})

import AuthContext from '...'
import {useContext} from 'react'
...
const authContext = useContext(AuthContext);

补充
Static properties are properties of a class, not of an instance of a class.
https://medium.com/front-end-weekly/understanding-static-in-javascript-10782149993
Useful Resources & Links:

上一篇下一篇

猜你喜欢

热点阅读