美文网首页
*【需要升入理解】React deeper into Compo

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

作者: 33jubi | 来源:发表于2020-05-25 22:37 被阅读0次

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

    A better project structure
    • components
    • contsainers
    • assets
    • splitting an app into components
    
    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
    • ‘Lifecycle Hooks’ have nothing to do with ‘React Hooks’
    • (ES6 feature=>)constructor(props)=>[1.Call super(props); 2.Do:set state; 3.Don’t set side-effect(http requests/store sth in localStorage in browsers);(ES7 do not need)]
    • getDerivedStateFromProps(props,state)=>[1.Do: Sync state; 2.Don’t set side-effect]
    • render()=>[prepare & Structure ur JSX Code]
    • Render Child Components
    • ComponentDidMount()[1.Do: Side-effect; 2.Don’t update state]
    • ComponentWillMount()
      static getDerivedSTateFromProps(props,state){}
    Component Lifecycle--Update
    • getDerivedStateFromProps(props,state)=>[1.Do: Sync state; 2.Don’t cause side-effect]
    • (may cancel updating process=>)shouldComponentUpdate(nextProps,nextState)=>[1.Do:decide whether to contiue or not;2.Dont’t:Cause side-effect]
    • render()=>[prepare & Structure ur JSX Code]
    • Update Child Components
    • getSnapshotBeforeUpdate(prevProps,prevState)[1.Last-minute DOM ops;2.Dont’t:Cause side-effect]
    • ComponentDidUpdate()[1.Do: Cause Side-effect; 2.Don’t update state]
      shouldComponentUpdate(nextProps,nextState)return true or false, when false stop 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

    • it runs before the main useEffect function
    • after the first render cycle
    • 只有在组件被‘clean up’才会run
    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
    • 父组件包子组件,当父组件state变化默认会render他的所有内部组件,
      这时候某些子组件并不需要跟新,因为与他相关的值并没有发生改变
    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]
    • 解释: 父组件包子组件,当父组件state变化默认会render他的所有内部组件,
      这时候某些子组件并不需要跟新,因为与他相关的值并没有发生改变,比如一个function component他只用到一个props中一个attr,所以希望通过一种方式减少不必要的render
    • 解释:
      比如一个function component他只用到一个props中一个attr,但是props每个属性改变都会造成他的rerender,所以希望通过一种方式减少不必要的render
    • 使用注意:传props给他时只传相关值,比如我要用this.state.persons.age, 那在传递参数时
      就只传递Dothis.state.persons.age,而不是Don’tthis.state.persons
    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
    • 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>
    )
    
    • Another Form of Hocs
      对于function 的js
    • 小写开头.js=>function
    • 大写开头.js=>functional component
    //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
    • 在setState中不要引用old state来更新new state
    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()
    • contextType class based
    import AuthContext from '...'
    static contexType = Authontext;
    
    componentDidMount(){
      var a = this.context.Authontext
    }
    return(...{this.context.Authontext})
    
    
    • useContext() function based
      in functional component
    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:

    相关文章

      网友评论

          本文标题:*【需要升入理解】React deeper into Compo

          本文链接:https://www.haomeiwen.com/subject/buqpahtx.html