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