React 7

7.86 Deeper into Components and React Internals

 

import React, { Component } from 'react';
import './App.css';


import Persons from '../components/Persons/Persons';
import Cockpit from '../components/Cockpit/Cockpit';


//use as many as function components as possible
//containers be as lean as possible


class App extends Component {
  state = {
    persons: [
      {id:'1', name: 'Max', age: 28 },
      {id:'2', name: 'Manu', age: 29 },
      {id:'3', name: 'Stephanie', age: 26 }
    ],
      otherState: 'some other value',
      showPersons: false

  }

  switchNameHandler = (newName) => {
    // console.log('Was clicked!');
    // DON'T DO THIS: this.state.persons[0].name = 'Maximilian';
    this.setState( {
      persons: [
        {name: newName, age: 28 },
        {name: 'Manu', age: 29 },
        {name: 'Stephanie', age: 27 }
      ]
    } )
  }

    nameChangedHandler = (event, id) => {
        const personIndex = this.state.persons.findIndex(p => {
            return p.id === id;//这个看不懂


        });

        const person = { ...this.state.persons[personIndex] };

        person.name = event.target.value;

        const persons = [...this.state.persons];
        persons[personIndex] = person;

        this.setState({
            persons: persons
        });
  }

    togglePersonsHandler = () => {

        const doesShow = this.state.showPersons;
        this.setState({showPersons: !doesShow});

    }

    deletePersonHandler = (personIndex) => {
        const persons = this.state.persons.slice();
        //const persons = [...this.state.persons];
        persons.splice(personIndex, 1);
        this.setState({ persons: persons });///bhb

    }

    render() {
        

        let persons = null;
        if(this.state.showPersons){
            persons = <Persons
                        persons={this.state.persons}
                        clicked={this.deletePersonHandler}
                        changed={this.nameChangedHandler}
                    />
                
            ;



    return (
      <div className="App">
            <Cockpit
                showPersons={this.state.showPersons}
                persons={this.state.persons}
                clicked={this.togglePersonsHandler}
            />
            {persons}
          
      </div>
    );
    // return React.createElement('div', {className: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

 

import React from 'react';
//import '.../containers/App.css'
import styled from 'styled-components';

const cockpit = (props) => {

    const StyledButton = styled.button`

            background-color: ${props => props.alt ? 'red' : 'green'};
            color: white;
            font: inherit;
            border: 1px solid blue;
            padding: 8px;
            cursor: pointer;
            &:hover {
                background-color: ${props => props.alt ? 'blue' : 'salmon'};
                color: black;
            }

        `;





    let classes = [];
    if (props.persons.length <= 2) {
        classes.push('red');//push red 给这个array
    }
    if (props.persons.length <= 1) {
        classes.push('bold');
    }


    return (
        <div>
            <h1>Hi, I'm a React App</h1>
            <p className={classes.join(' ')}>This is really working!</p>
            <StyledButton alt={props.showPersons}
                onClick={props.clicked}>Switch Name</StyledButton>
        </div>);

};
//报错:return multiple outputs without root node(用《div》括起来)
export default cockpit;

 87 stateful stateless

presentational state(stateless)a functional components dont use state

 

 

index.js

ReactDOM.render(<App appTitle="Person Manager"/>, document.getElementById('root'));

 

 

 

 

 

 89 class component lifecycle

 

 

 

 

 

 

 change functional component into class based component

import React from 'react';
/*import './Person.css';*/
/*import Radium from 'radium';*/
import styled from 'styled-components';


const StyledDiv = styled.div`


    width:60%;
    margin:16px;
    border:1px solid #eee;
    box-shadow: 0 2px 3px #ccc;
    padding: 16px;
    text-align: center;




`;

const person = ( props ) => {
    return (
        /*<div className="Person">*/
            <StyledDiv>
            <p onClick={props.click}>I'm {props.name} and I am {props.age} years old!</p>
            <p>{props.children}</p>
            <input type="text" onChange={props.changed} value={props.name} />
        </StyledDiv>
    )
};

export default person;

 

useEffect() in functional components

    useEffect(() => {
        console.log("cockpitjs useEffect");

    });

useeffect 一直会render

下面只有persons change了 才会rerender 如果是【】则只有第一次和unmount时生效

    useEffect(() => {
        console.log("cockpitjs useEffect");

        setTimeout(() => {

            alert("saved");
        }, 1000); 一秒后有个alert 测试用
    }, [props.persons]);//当什么元素执行的时候 如果数组里没有元素 则只有第一次render

    //useEffect(可以加其他的effect)

return代表componentwillunmount 即这个组件被remove了那就会有console.log 但是除非它被remove 否则一直不会有log(在first render cycle 以后 但其他之前)

 return () => {
           /* clearTimeout(timer);*/
            console.log("cockpit js cleanup");//this is not shown because cockpit is never removed?           


        };

搞清楚 real dom virtual dom  render

7.97 class-based:shouldConponentUpdate

  shouldComponentUpdate(nextProps, nextState) {
        console.log("shouldComponentUpdate personjs");
        if (nextProps !== this.props) {
            return true;
        } else {

            return false;
        }

如果有改动,就重新render

7.98 Optimizing Functional Components
with React.memo()

 if (props.personslength <= 1) {
        classes.push('bold');
    }
export default React.memo(cockpit);

 

if use memo  only rerender when props change

 

 

 there is no

 

 7.100

 

import React, { Component} from 'react';

import styled from 'styled-components';




class Person extends Component {//大写class name

    static getDerivedStateFromProps(props, state) {

        console.log("getDerivedStateFromProps personjs");
        return state;
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log("shouldComponentUpdate personjs");
        if (nextProps !== this.props ||
            nextProps.changed !==this.props.changed


        ) {
            return true;
        } else {

            return false;
        }

等于

import React, { PureComponent} from 'react';
/*import './Person.css';*/
/*import Radium from 'radium';*/
import styled from 'styled-components';




class Person extends PureComponent {

自带shouldComponentUpdate 查重所有props

7.101

 

 

102 Rendering Adjacent JSX Elements

<Div>
                <p onClick={this.props.click}>I'm {this.props.name} and I am {this.props.age} years old!</p>
                <p>{this.props.children}</p>
                <input type="text" onChange={this.props.changed} value={this.props.name} />
            </Div>//props前加上this

==

<p key=“1” onClick={this.props.click}>I'm {this.props.name} and I am {this.props.age} years old!</p>,
                <p key=“2”>{this.props.children}</p>,
                <input key=“3” type="text" onChange={this.props.changed} value={this.props.name} />
】

 

 

 

 

 

 

 

 HOC

 

 

 

 

 

 107 passing unknown props

 

person.js

import React, { Component } from 'react'; import Aux from '../../../hoc/Auxillary'; import withClass from '../../../hoc/withClass'; import classes from './Person.css'; class Person extends Component { render() { console.log('[Person.js] rendering...'); return ( <Aux> <p onClick={this.props.click}> I'm {this.props.name} and I am {this.props.age} years old! </p> <p key="i2">{this.props.children}</p> <input key="i3" type="text" onChange={this.props.changed} value={this.props.name} /> </Aux> ); } } export default withClass(Person, classes.Person);
withClass.js


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

 

aux.js
const aux = props => props.children; export default aux;

108.setState correctly

 

 用这个而不是

 

 因为这个不能保证this.state是上一个state

109:Using PropTypes

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import Aux from '../../../hoc/Auxillary';
import withClass from '../../../hoc/withClass';
import classes from './Person.css';

class Person extends Component {
  render() {
    console.log('[Person.js] rendering...');
    return (
      <Aux>
        <p onClick={this.props.click}>
          I'm {this.props.name} and I am {this.props.age} years old!
        </p>
        <p key="i2">{this.props.children}</p>
        <input
          key="i3"
          type="text"
          onChange={this.props.changed}
          value={this.props.name}
        />
      </Aux>
    );
  }
}


Person.propTypes = {
    click: PropTypes.func,
    name: PropTypes.string,
    age: PropTypes.number,
    changed: PropTypes.func


};

export default withClass(Person, classes.Person);

类型检查,没有符合,加warning

110 using ref

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import Aux from '../../../hoc/Auxillary';
import withClass from '../../../hoc/withClass';
import classes from './Person.css';

class Person extends Component {
    componentDidMount() {
        this.inputElement.focus();

    }


  render() {
    console.log('[Person.js] rendering...');
    return (
      <Aux>
        <p onClick={this.props.click}>
          I'm {this.props.name} and I am {this.props.age} years old!
        </p>
        <p key="i2">{this.props.children}</p>
        <input
                key="i3"
                ref={(inputEl) => {this.inputElement=inputEl }}
          type="text"
          onChange={this.props.changed}
          value={this.props.name}
        />
      </Aux>
    );
  }
}


Person.propTypes = {
    click: PropTypes.func,
    name: PropTypes.string,
    age: PropTypes.number,
    changed: PropTypes.func


};

export default withClass(Person, classes.Person);

111 ref with react hook

import React, { useEffect,useRef } from 'react';

import classes from './Cockpit.css';

const Cockpit = props => {
    const toggleBtnRef = React.createRef(null);
    /*toggleBtnRef.current.click();*/

  useEffect(() => {
    console.log('[Cockpit.js] useEffect');
    // Http request...
    /*setTimeout(() => {
      alert('Saved data to cloud!');
    }, 1000);*/
      toggleBtnRef.current.click();
    return () => {
      console.log('[Cockpit.js] cleanup work in useEffect');
    };
  }, []);

  useEffect(() => {
    console.log('[Cockpit.js] 2nd useEffect');
    return () => {
      console.log('[Cockpit.js] cleanup work in 2nd useEffect');
    };
  });

  // useEffect();

  const assignedClasses = [];
  let btnClass = '';
  if (props.showPersons) {
    btnClass = classes.Red;
  }

  if (props.personsLength <= 2) {
    assignedClasses.push(classes.red); // classes = ['red']
  }
  if (props.personsLength <= 1) {
    assignedClasses.push(classes.bold); // classes = ['red', 'bold']
  }

  return (
    <div className={classes.Cockpit}>
      <h1>{props.title}</h1>
      <p className={assignedClasses.join(' ')}>This is really working!</p>
          <button ref={toggleBtnRef} className={btnClass} onClick={props.clicked}>
        Toggle Persons
      </button>
    </div>
  );
};

export default React.memo(Cockpit);

不能放在上面 放在上面 渲染时候下面jsx代码还没有渲染 会报错,故放在useffect里 在render结束后发生

functional component只能用这个react hook

 

 

 

 

posted @ 2020-03-05 14:32  cschen588  阅读(180)  评论(0编辑  收藏  举报