react研究

MV*&组件化开发react专题

react介绍与react代码规范

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OG8yz88q-1571282357731)(en-resource://database/975:1)]
配置了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UfULnTlj-1571282357732)(en-resource://database/977:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v6Fv8V4c-1571282357732)(en-resource://database/979:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xW9a6q2T-1571282357733)(en-resource://database/981:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIw6DDkS-1571282357733)(en-resource://database/985:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzkxfxX2-1571282357734)(en-resource://database/987:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLLpSIM3-1571282357734)(en-resource://database/989:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5pLsdRPL-1571282357735)(en-resource://database/991:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lTMVu6vK-1571282357735)(en-resource://database/993:1)]

虚拟DOM和jsx

react组件和变量有本质区别
组件是有生命周期的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVtBQARb-1571282357736)(en-resource://database/995:1)]
第一个和第二个是同一个类的两个实例化对象,是两个不同的组件
下面两个list是同一个变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KidI21YB-1571282357737)(en-resource://database/997:1)]
是es6组件的简写方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RyruJiVv-1571282357737)(en-resource://database/999:1)]
react虚拟dom不能渲染对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-viddoNnO-1571282357738)(en-resource://database/1001:1)]
原理:

  1. 把jsx编译成js,把过去构建DOM树的浏览器的工作交给js
  2. 把结构数据传入react render方法,将js的数据结构渲染出来

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-594mrMVZ-1571282357738)(en-resource://database/1007:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyadW7aL-1571282357739)(en-resource://database/1009:1)]
header组件会被卸载content组件会被挂载


class List extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
        data: ['react', 'vue', 'angular']//=>['vue','angular'] 当组件没有key属性时,渲染会一一对应,react和vue会update,angular会被删掉
        }
    }
    render () {
        return (
            <div>
            {this.state.data.map(item => <Item value={item} key={item}/>)}
            </div>
        )
    }
    componentDidMount () {
        window.list = this
    }
}


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sAboEhih-1571282357739)(en-resource://database/1011:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTH0OvZb-1571282357739)(en-resource://database/1013:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RXftc8Hv-1571282357740)(en-resource://database/1015:1)]

生命周期与数据操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4lY5qDI1-1571282357740)(en-resource://database/1034:1)]
Component这个类实现了生命周期的一系列方法
react只有数据和生命周期两个概念


class Component {
    setState(){}
    readonly props
    componentDidUpdate(prevProps,prevState){
    }
    componentDidMount(){
    }
    ...
}


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrH6vGCl-1571282357741)(en-resource://database/1036:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HboBqo0v-1571282357741)(en-resource://database/1038:1)]
一个父组件只有在他的子组件全都挂载完成以后才会执行自己的componentDidMount
生命周期函数。

父组件会首先渲染,执行render函数,然后依次渲染他下面的子组件


import React,{Component} from 'react';
class App extends Component{
    constructor(props){
        super(props)
        this.state = {
            name: 'react'
        }
    }
    render() {
        console.log('App rerender')
        return (
            <div>
                {this.state.name}
                {this.state.name && <Son1 name={this.state.name + '-son'}/>}
            </div>
        );
    }
    componentDidMount() {
        window.app = this
        console.log('App mount')
    }
    componentWillUpdate(nextProps, nextState) {
        console.log('App will update')
    }
    componentDidUpdate(prevProps, prevState) {
        console.log('App did update')
    }
}
class Son1 extends Component{
    render() {
        console.log('son1 rerender')
        return (
            <div>
                {this.props.name}
                <GrandSon1 name={this.props.name + '-grand'}/>
            </div>
        );
    }
    componentDidMount() {
        console.log('Son1 mount')
    }
    componentWillUpdate(nextProps, nextState) {
        console.log('son1 will update')
    }
    componentDidUpdate(prevProps, prevState) {
        console.log('son1 did update')
    }
    componentWillUnmount() {
        console.log('Son1 unmout')
    }
}
class GrandSon1 extends Component{
    render() {
        console.log('GrandSon1 rerender')
        return (
            <div>
                {this.props.name}
            </div>
        );
    }
    componentDidMount() {
        console.log('GrandSon1 mount')
    }
    componentWillUpdate(nextProps, nextState) {
        console.log('GrandSon1 will update')
    }
    componentDidUpdate(prevProps, prevState) {
        console.log('GrandSon1 did update')
    }
    componentWillUnmount() {
        console.log('GrandSOn1 unmout')
    }
}
export default App


当父组件改变数据时,父组件先update和render,他的子组件依次更新,完成更新是最后代的组件先完成更新
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cF03bWJE-1571282357742)(en-resource://database/1040:1)]

销毁组件的时候是从上往下销毁,先销毁子组件,后销毁孙组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4oWrIJHl-1571282357742)(en-resource://database/1042:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NNv8bKS3-1571282357743)(en-resource://database/1044:1)]

react上下文 组件在嵌套层次比较深的时候,数据从最外层组件传到最内层组件


import React from 'react';
import PropTypes from 'prop-types'
class App extends React.Component {
    getChildContext() {
        return {color: "purple"};
    }
    constructor(props){
        super(props)
        this.state = {
            name: 'son'
        }
    }
    render() {
        console.log('App rerender')
        return (
            <div>
                {this.state.name && <Son1 name={this.state.name}/>}
            </div>
        );
    }
    componentDidUpdate(prevProps, prevState) {
        console.log('App did update')
    }
    componentWillUpdate(prevProps, prevState) {
        console.log('App will update')
    }
    componentDidMount() {
        console.log('app mount')
        window.app = this
    }
}
App.childContextTypes = {
    color: PropTypes.string
}
class Son1 extends React.Component{
    render() {
        console.log('Son1 rerender')
        return (
            <div>
                {this.props.name && <GrandSon1 name={this.props.name + '-grand'}/>}
            </div>
        );
    }
    componentWillUpdate(prevProps, prevState) {
        console.log('son will update')
    }
    componentDidUpdate(prevProps, prevState) {
        console.log('son did update')
    }
    componentDidMount() {
        console.log('son mount')
    }
    componentWillUnmount() {
        console.log('son unmount')
    }
}
class GrandSon1 extends React.Component{
    render() {
        console.log('GrandSon1 rerender')
        return (
            <div>
                {this.props.name} - {this.context.color}
            </div>
        );
    }
    componentWillUpdate(prevProps, prevState) {
        console.log('son will update')
    }
    componentDidUpdate(prevProps, prevState) {
        console.log('GrandSon1 did update')
    }
    componentDidMount() {
        console.log('grandson mount')
    }
    componentWillUnmount() {
        console.log('GrandSon1 unmount')
    }
}
GrandSon1.contextTypes = {
    color: PropTypes.string
};
export default App;


组件通信

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LIFtqAg5-1571282357744)(en-resource://database/1046:1)]
父组件到子组件的通信是父组件拿到子组件的实例,然后调用子组件的方法,该操作不是react的风格

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PppK45Bf-1571282357744)(en-resource://database/1048:1)]


import React,{Component} from 'react';
import './App.css';
class List extends Component{
    constructor(props) {
        super(props);
        this.state = {
            data: [
                {name: 'a',id:0},
                {name: 'b',id:1},
                {name: 'c',id:2}
            ],
        }
    }
    render() {
        return (
            <div>
                {this.state.data.map(item => <p key={item.id}>{item.name}</p>)}
            </div>
        );
    }
    clear() {
        this.setState({
            data: []
        })
    }
}
class App extends React.Component{
    render() {
        return (
            <div>
                 <List ref='list'/>
            </div>
        );
    }
    componentDidMount() {
        window.app = this
        //父组件向子组件的通信 慎用
        this.refs.list拿到list组件的实例对象
        // this.refs.list.clear()
    }
}
export default App;


观察者模式 不推荐


import React,{Component} from 'react';
import './App.css';
class EventComponent extends Component{
    cb = {}
    on(name,cb) {
        this.cb[name] = cb
    }
    off(name) {
        delete this.cb[name]
    }
    trigger(name,arg) {
        this.cb[name](arg)
    }
}
class List extends EventComponent{
    constructor(props) {
        super(props);
        this.state = {
            data: [
                {name: 'a',id:0},
                {name: 'b',id:1},
                {name: 'c',id:2}
            ],
        }
    }
    render() {
        return (
            <div>
                {this.state.data.map(item => <p key={item.id}>{item.name}</p>)}
            </div>
        );
    }
    clear() {
        this.setState({
            data: []
        })
    }
    add(name) {
        let {
            data
        } = this.state
        data.push({
            name,
            id:name
        })
        this.setState({data})
    }
}
class Action extends EventComponent{
    constructor(props) {
        super(props);
        this.state = {
            value: ''
        }
    }
    render() {
        return (
            <div>
                <input value={this.state.value} onChange={(e) => this.setState({value: e.target.value })}/>
                <button onClick={(e) =>{
                    this.trigger('add', this.state.value)
                }}>add</button>
            </div>
        );
    }
}
class App extends EventComponent{
    render() {
        return (
            <div>
                 <List ref='list' />
                <Action ref='action'/>
            </div>
        );
    }
    componentDidMount() {
        let listInstance = this.refs.list
        let actionInstance = this.refs.action
        actionInstance.on('add',(name) => {
            listInstance.add(name)
        })
        window.app = this
        // this.refs.list.clear()
    }
}
export default App;


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7PxZVgSl-1571282357745)(en-resource://database/1050:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z9hjhykL-1571282357745)(en-resource://database/1052:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiZfmI5S-1571282357745)(en-resource://database/1054:1)]

ReactDom与表单

react与dom操作结合


import ReactDOM from "react-dom";
import React from "react";
import './index.css'
class Loading extends React.Component{
    render() {
        return (
            <div className='loading'>
                <div className='loading__mask'></div>
                <div className='loading__content'>
                    loading
                </div>
            </div>
        );
    }
}
let node = null
const loading = {
    show() {
        node = document.createElement('div')
        document.body.appendChild(node)
        //挂载Loading组件
        ReactDOM.render(<Loading />, node)
    },
    hide() {
        if(node) {
        //卸载Loading组件 
            ReactDOM.unmountComponentAtNode(node)
            document.body.removeChild(node)
        }
    }
}
export default loading


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d1uI9Z0W-1571282357746)(en-resource://database/1056:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-orOWrRGE-1571282357746)(en-resource://database/1058:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJfl6kKg-1571282357747)(en-resource://database/1060:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajtJ7tiq-1571282357747)(en-resource://database/1062:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aC9RQfjC-1571282357747)(en-resource://database/1064:1)]

react与es6

  1. 变量的赋值与解构
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ef0CWb6-1571282357748)(en-resource://database/1066:1)]
    数组的解构
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ael5WybB-1571282357748)(en-resource://database/1068:1)]
    对象的解构和扩展

import React from 'react';
import logo from './logo.svg';
import './App.css';
class  App extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            name: 'react & es6',
            lesson: '6',
            teacher:{
                teacherName:'ryan',
                age:30
            },
            skills:['vue','react','nodejs','webpack'],
            friend:{
                name:'aa'
            }
        }
    }
    render() {
        let {
            name,
            lesson,
            teacher:{
                teacherName,
                age
            },
            skills:[vue1, react1,nodejs1,webpack1],
            friend:{
                name: friendName
            }
        } = this.state
        return (
            <div>
                <p>{name} - {lesson}</p>
                <p>
                    {teacherName} - {age}
                </p>
                <p>
                    {vue1} - {react1} - {nodejs1} - {webpack1}
                </p>
                <p>{friendName}</p>
        App
            </div>
        );
    }
}
export default App;



import React from 'react';
import ReactDOM from 'react-dom'
import inp from './input'
class User extends React.Component{
    render() {
        const {
            name,
            age,
            lesson,
            ...rest
        } = this.props
        return (
            <div {...rest}>
                {name} - {age} - {lesson}
            </div>
        );
    }
}
class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name:'ryan',
            age:30,
            lesson:'react'
        }
    }
    render() {
        let {
            name,
            age,
            lesson
        } = this.state
        return (
            <div>
                <User
                    name={name}
                    age={age}
                    lesson={lesson}
                    style={{color:'red'}}
                    onClick={() =>{
                        alert('hello')
                    }}
                    onMouseOver={() => {
                    }}
                />
            </div>
        )
    }
}
export default App;
  1. 类的继承

import React from 'react';
import ReactDOM from 'react-dom'
import inp from './input'
class LogComponent extends React.Component{
    componentWillUnmount() {
        console.log('app','unmount')
    }
}
class App extends LogComponent{
    render() {
        return (
            <div>
                app
            </div>
        );
    }
}
export default App;


实现loading继承


import React from 'react';
import ReactDOM from 'react-dom'
import inp from './input'
class LoadingComponent extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            loading: false
        }
    }
    render() {
        const {
            loading
        } = this.state
        return (
            <div>
                {loading ? 'loading....' : ''}
            </div>
        );
    }
    showLoading() {
        this.setState({
            loading: true
        })
    }
    hideLoading(){
        this.setState({
            loading: false
        })
    }
}
class App extends LoadingComponent{
    render() {
        return (
            <div>
            //super表示被继承的基类
                {super.render()}
                app
            </div>
        );
    }
    componentDidMount() {
        this.showLoading()
        setTimeout(() => {
            this.hideLoading()
        },3000)
    }
}
let obj = new Proxy({
    a:10,
    b:20
}, {
    get: function (target,key,) {
        console.log('get ',key)
        return target[key] * 10
    },
    set: function (target,key,value) {
        return Reflect.set(target,key,value)
    }
})
window.obj = obj
export default App;


  1. Proxy 拦截器
//两个参数 1目标对象 2处理器有get和set
let obj = new Proxy({
    a:10,
    b:20
}, {
    get: function (target,key,) {//target即为第一个参数
        console.log('get ',key)
        return target[key] * 10
    },
    set: function (target,key,value) {
    //Object.assign()
    //Object.keys()
    //Reflect相当于Object,未来给对象新添的方法只部署在Reflect上
        return Reflect.set(target,key,value)
    }
})


  1. Decorator装饰器
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCSM7w0S-1571282357749)(en-resource://database/1070:1)]

class Math {
    @log
    add(a, b) {
        return a + b;
    }
}
function log(target, name, descriptor) {
    //参数1是所要修饰的目标对象,即类的实例(这不同于类的修饰,那种情况时target参数指的是类本身);参数2是所要修饰的属性名,参数3是该属性的描述对象
    var oldValue = descriptor.value
    descriptor.value = function () {
        console.log(`Calling ${name} with`, arguments)
        return oldValue.apply(this, arguments)
    }
    return descriptor;
}
const math = new Math();
math.add(1, 2)



import React from 'react';
import ReactDOM from 'react-dom'
let loading = (Com) => {
    class LoadingComponent extends Com {
        constructor(props) {
            super(props);
            this.state = {
                loading: false
            }
        }
        render() {
            const {
                loading
            } = this.state
            return (
                <div>
                    {super.render()}
                    {loading ? 'loading....' : ''}
                </div>
            );
        }
        showLoading() {
            this.setState({
                loading: true
            })
        }
        hideLoading() {
            this.setState({
                loading: false
            })
        }
    }
    return LoadingComponent
}
//@loading=>loading(App)返回一个新的组件继承自App
@loading
class App extends React.Component {
    render() {
        return (
            <div>
                app
            </div>
        );
    }
    componentDidMount() {
        this.showLoading()
    }
}
export default App;


async await 与promise


import React from 'react';
import ReactDOM from 'react-dom'
import axios from 'axios'
class App extends React.Component {
    render() {
        return (
            <div>
                app
            </div>
        );
    }
    getValue() {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve('ryan')
            }, 3000)
        })
    }
    async componentDidMount() {
        let {
            data: {
                data
            }
        } = await axios
            .get('http://localhost:7777/api')
        console.log(data)
        let value = await this.getValue()
        console.log(value)
    }//这段代码的意思是先请求接口,然后执行getValue()
    
    //babel编译成下面这个函数
    componentDidMount2() {
        axios
            .get('http://localhost:7777/api').then(({
                data: {
                    data
                }
            }) => {
                console.log(data)
                this.getValue().then(value => {
                    console.log(value)
                })
            })
    }
}
export default App


自定义组件


import React,{Component} from 'react'
//更好拼接类名的插件
import classNames from 'classnames'
import PropTypes from 'prop-types'
import Icon from '../Icon'
import './index.scss'
class Input extends Component{
    constructor(props){
        super(props)
        this.state = {
            focus: false,
            innerValue: ''
        }
    }
    static propTypes = {
        value: PropTypes.string,
        onChange: PropTypes.func,
        size:PropTypes.string,
    }
    static defaultProps = {
        size: 'middle',
        onChange: () => {}
    }
    get isControl(){
        return 'value' in this.props
    }
    get value() {
        if(this.isControl){
            return this.props.value
        } else {
            return this.state.innerValue
        }
    }
    render() {
        const {
            focus
        } = this.state
        const {
            icon,
            children,
            size,
            prefix,
            suffix,
            onChange,
            rule= new RegExp(),
            message,
            ...rest
        } = this.props
        let cls = classNames({
            input: true,
            focus,
            [`size-${size}`]: true,
            'react-ui__input': true
        })
        return (
            <div>
            <div className={cls}>
                {prefix && <Icon name={prefix}/>}
                <input
                    value={this.value}
                    onFocus={e => {
                        this.setState({focus: true
                        })
                    }}
                    onBlur={e => {
                        this.setState({focus: false
                        })
                    }}
                    onChange={(e) => {
                        if(!this.isControl){
                            this.setState({
                                innerValue: e.target.value
                            })
                        }
                        this.props.onChange(e)
                    }}
                />
                {suffix && <Icon name={suffix}/>}
            </div>
                <p>
                    {!rule.test(this.value) && message}
                </p>
            </div>
        )
    }
    componentDidMount() {
        this.setState({
            innerValue: this.props.defaultValue
        })
    }
}
export default Input


受控 特点就是有value,必须有value和onChange才能改变表单的值
 非受控 defaultValue,输入框里的值可以改变,不需要onChange


//非受控组件可以直接给某个变量赋值,不需要setState
<Input
    rule={/\d/}
    message="只允许输入数字"
    size='small' defalutValue={this.value} onChange={(e) => {
    this.value = e.target.value
}}/>


高阶组件

模拟redux的connect方法


import React from "react";
import PropTypes from 'prop-types'
class Provider extends React.Component {
    getChildContext() {
        return this.props.store
    }
    static childContextTypes = {
        name: PropTypes.string,
        age: PropTypes.number
    }
    constructor(props) {
        super(props)
        this.state = {
            name: 'provider-user'
        }
    }
    render() {
        return this.props.children
    }
}
class BaseUser extends React.Component {
    render() {
        return (
            <div>
                {this.props.name}
            </div>
        );
    }
}
class BasePost extends React.Component {
    render() {
        return (
            <div>
                {this.props.age}
            </div>
        );
    }
}
const connect = (Com) => {
    class ConnectComponent extends React.Component {
        static contextTypes = Provider.childContextTypes
        //将ConnectComponent组件的名字改为传进来Com组件的名字
        displayName = Com.displayName
        render() {
            return (
                <Com {...this.context} />
            );
        }
    }
    return ConnectComponent
}
const User = connect(BaseUser)
const Post = connect(BasePost)
const store = {
    name: 'ryan',
    age: 10
}
class App extends React.Component {
    render() {
        return (
            <Provider store={store}>
                <div>
                    <User />
                    <Post />
                </div>
            </Provider>
        );
    }
}
export default App


模拟@connect方法


import React,{Component} from "react";
import PropTypes from 'prop-types'
// 用于预先 将业务组件,进行数据的封装,便于我们 方便获取数据
// 反向继承
const connect = key => Com  => {
//属性代理,继承原生的component,一定要用render方法
    class connectComponent extends Component {
        constructor(props){
            super(props)
            this.state = {
                [key]: store[key]
            }
        }
        render() {
            return <Com {...this.state}/>
        }
        componentDidMount() {
            let that = this
            window.store = new Proxy(store, {
                get: function (target, key, receiver) {
                    return Reflect.get(target, key, receiver);
                },
                set: function (target, key, value, receiver) {
                    that.setState({
                        [key]:value
                    })
                    return Reflect.set(target, key, value, receiver);
                }
            })
        }
    }
    return connectComponent
}
let store = {
    name: 'ryan',
    age: 10
}
@connect('age')
class User extends Component{
    render() {
        return <div>{this.props.age}</div>
    }
}
class App extends Component{
    render() {
        return <User/>
    }
}
export default App



import React, { Component } from "react";
import PropTypes from 'prop-types'
// 用于预先 将业务组件,进行数据的封装,便于我们 方便获取数据
// 反向继承 交互的封装,
const loading = Com => {
//反向继承,继承传入的类,不建议写render方法
    class LoadingComponent extends Com {
        //继承了Com的componentDidMount方法
        showLoading() {
            console.log('loading')
        }
        hideLoading() {
            console.log('hide')
        }
    }
    return LoadingComponent
}
@loading
class User extends Component {
    render() {
        return <div>user</div>
    }
    componentDidMount() {
        this.showLoading()
        //http
        this.hideLoading()
    }
}
class App extends Component {
    render() {
        return <User />
    }
}
export default App


React hooks

组件的组成
数据:props state
组件生命周期

函数式组件
定义和修改组件状态 useState


import React, { useState, useEffect } from 'react'
//函数式组件
const Action = (props) => {
    //定义状态 修改状态   传入初始状态
    const [value, setValue] = useState('js')
    const [sex, setSex] = useState('man')
    //函数式组件不能条件式的定义状态,即const [sex,setSex] = useState('man')不能放在if(){这里},否则该组件会找不到其中的某项状态
    return (
        <div>
            <input value={value} onChange={(e) => setValue(e.target.value)} />
            <button onClick={(e) => props.onAdd(value)}>add</button>
        </div>
    )
}
const List = (props) => {
    return (
        <div>
            {props.data.map(item => (
                <div key={item.id}>
                    <span>{item.name}</span><button>del</button>
                </div>
            ))}
        </div>
    )
}
const App = (props) => {
    const [data, setData] = useState([
        { name: 'react', id: 1 },
        { name: 'vue', id: 2 }])
    return (
        <div>
            <Action onAdd={(name) => {
                data.push({
                    name: name,
                    id: Math.random()
                })
                setData([...data])
            }} />
            <List data={data} />
        </div>
    )
}
export default App


组件生命周期
useEffect函数将componentDidMount和componentDidUpdate合并成一个方法

useEffect(()=>{
    console.log('hello')
    //当第二个参数传入[]空数组时,componentDidMount被触发
},[])

import React,{useState,useEffect,useRef} from 'react'
const useTitleHook = (title) => {
    useEffect(() => {
        document.title = title
        //当title的状态被改变时该函数才会被调用
    },[title])
}
const App = (props) => {
    let [title,setTitle] = useState('hello')
    useTitleHook(title)
    return (
        <div >
            sss
            <input value={title} onChange={(e) => setTitle(e.target.value)}/>
        </div>
    )
}
export default App


componentWillUnMount组件被销毁时,函数式组件的写法


useEffect(() => {
       console.log('hello')
       return ()=>{
       //组件被销毁时触发
       console.log('status clear')
    },[title])


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IWooatab-1571282357749)(en-resource://database/1074:1)]

自定义hook


import React, { useState, useEffect, useRef } from 'react'
const useTitleHook = (title) => {
    useEffect(() => {
        document.title = title
        return () => {
            document.title = 'title'
        }
    })
}
const App = (props) => {
    let [title, setTitle] = useState('hello')
    useTitleHook(title)
    return (
        <div >
            sss
            <input value={title} onChange={(e) => setTitle(e.target.value)} />
        </div>
    )
}
export default App


React与Typescript

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHepYuEE-1571282357750)(en-resource://database/1076:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lpq7W6Wn-1571282357750)(en-resource://database/1078:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rl1qVSiJ-1571282357751)(en-resource://database/1080:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cRl02MMr-1571282357751)(en-resource://database/1082:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4SsZeR2o-1571282357751)(en-resource://database/1084:1)]
class不能创建一个抽象类的实例
抽象类里的方法只能通过继承该抽象类和继承类的实例调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-utOLEvI9-1571282357751)(en-resource://database/1086:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QJhJi830-1571282357752)(en-resource://database/1088:1)]

通过以下指令创建ts版本的react项目
 create-react-app my-app --scripts-version=react-scripts-ts && cd my-app


import * as React from 'react';
import {FriendItem} from "../types";
interface onDel {
  (index: number): void
}
interface IProps {
  list: Array<FriendItem>,
  onDel: onDel
}
class List extends React.Component<IProps>{
  render() {
    const {
      list,
      onDel
    } = this.props
    return (
      <div>
        {list.map((item: FriendItem,index: number) => <div>
          {item.name} <button onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
          onDel(index)
        }}>-</button>
        </div>)}
      </div>
    );
  }
}
export default List


数据管理-Redux

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ln27dfeP-1571282357752)(en-resource://database/1090:1)]

//reducer表示store仓库里面的房间
//reducer这个入口里面有将各个不同房间整合起来的功能:combineReducers
import { combineReducers } from 'redux'
import title from './title'
import friend from './friend'
export default combineReducers({
  title,
  friend
  // friend,
  // post
})


//action表示发号施令,各个房间接受这个指令,对store里面的的数据做各种各样的修改,返回最新的数据给页面使用
//store是数据管理的总仓库,仓库里有dispatch这个属性
import { store } from '../store';
export const UPDATE_TITLE = 'UPDATE_TITLE'
export function updateTitle(data) {
  const dispatch = store.dispatch
  dispatch({ type: UPDATE_TITLE, data })
}

js数据解构时当里面的数据发生变化时,这时候它是对象的话,则它的内存地址没有发生变化,即对象里面的某个属性值发生变化后该对象的内存地址没有改变则js捕捉不到该对象的变化
js只会认为当前对象解构的数据的内存地址发生变化时这个数据才发生了变化


import { ADD_FRIEND, DEL_FRIEND } from '../actions/friend'
const initialState = {
  list: [
    {
      name: 'ryan', id: 1
    },
    {
      name: 'xiao', id: 2
    }
  ]
}
export default (state = initialState, action = {}) => {
  const { type, data } = action
  let list = state.list
  switch (type) {
    case ADD_FRIEND:
      list = state.list
      list.push(data)
      //list要保证是个新的,发生变化了页面才会重新渲染
      return Object.assign({}, state, { list: [...list] })
    case DEL_FRIEND:
      list = list.filter(item => item.id !== data)
      return Object.assign({}, state, { list: [...list] })
    default:
      return state
  }
}


redux hook
没有定义全局的store,没有统一管理的地方,这里的store有redux-hook帮我们统一管理了


import React, { useReducer } from 'react'
import { render } from 'react-dom'
import Provider from 'react-redux/es/components/Provider'
import { store } from './store'
import App from './App'
const initialState = { count: 1 }
function reducer (state, action) {
  switch (action.type) {
    case 'reset':
      return initialState
    case 'increment':
      return { count: state.count + 1 }
    case 'decrement':
      return { count: state.count - 1 }
    default:
      // A reducer must always return a valid state.
      // Alternatively you can throw an error if an invalid action is dispatched.
      return state
  }
}
function Counter ({ initialCount }) {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <div>
        Count: {state.count}
      <button onClick={() => dispatch({ type: 'reset' })}>
          Reset
      </button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  )
}
render(
  <Counter />,
  document.getElementById('root')
)


数据管理 Mobx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2StkqnO-1571282357753)(en-resource://database/1092:1)]

简单应用


import React,{Component} from 'react';
import {
    observable
} from 'mobx'
import {
    observer
} from 'mobx-react';

//装饰器,将App变成响应式组件
@observer
class App extends Component{
  
//响应式变量
    @observable value = 'a'
    constructor(props){
        super(props)
        this.state = {
            time: 0
        }
    }
    render() {
        const {
            time
        } = this.state
        return (
            <div>
                app
                <input value={this.value} onChange={e => this.value = e.target.value}/>
                {this.value}
            </div>
        );
    }
    componentDidMount() {
    }
}
export default App;


复杂应用

  1. 入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import {
    Provider
} from 'mobx-react'
import './index.css';
import App from './App3';
import * as serviceWorker from './serviceWorker';
import store from './store'
window.store = store
ReactDOM.render(
    <Provider {...store}>
        <App />
    </Provider>
    , document.getElementById('root'));
window.ReactDOM = ReactDOM
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
// a 删除
// b,c 更新
// d 创


2.store里面的数据


import friend from './friend'
import post from './post'
export default {
    friend,
    post
}



import {
    observable,computed,
    autorun
} from 'mobx'
import post from './post'
class Friend {
    @observable list = [
        {
            name:'ryan',
            id:1
        },
        {
            name:'xiao a',
            id:2
        },
        {
            name: 'xiao c',
            id: 3
        }
    ]
    @observable activeId = 1
    @computed//计算属性,只要return 里面的值发生了变化之后,被装饰的friendPost函数会自动执行
    get friendPost(){
        return post.list.filter(item => item.friendId === this.activeId)
    }
}
const friend = new Friend()
export default friend



import {
    observable,
    action
} from 'mobx'
const addForm = {
    title : '',
    content : '',
    friendId : '',
}
class Post {
     @observable list = [
        {
            title:'hello ryan',
            content: 'hello ryan post 1',
            id:1,
            friendId:1
        },
        {
            title:'hello ryan 1',
            content: 'hello ryan post 2',
            id:2,
            friendId:1
        },
        {
            title:'hello ryan 2',
            content: 'hello ryan post 3',
            id:3,
            friendId:1
        }
    ]
 }
const post = new Post()
export default post


3渲染组件


import React,{Component} from 'react';
import {
    observable,
} from 'mobx'
import Friend from './views/friend'
import Post from './views/post'
import Action from './views/action'
import {
    observer,
    inject
} from 'mobx-react'
@inject('friend','post')//注入数据
@observer
class App extends Component{
    render() {
        console.log(this.props,'this.props')
        return (
            <div>
                <h2>好友列表</h2>
                <Friend/>
                <h2>全部说说</h2>
                <Post/>
                <Action/>
            </div>
        );
    }
    componentDidMount() {
    }
}
export default App;



import React,{Component}from 'react'
import {inject, observer} from "mobx-react";
@inject('friend')
@observer
class Friend extends Component{
    render() {
        const {
            friend
        } = this.props
        return (
            <div>
                |{friend.list.map(item => <span onClick={() => {
                    friend.activeId = item.id
            }} key={item.id}>{item.name} | </span>)}
            </div>
        );
    }
}
export default Friend



import React,{Component}from 'react'
import {inject, observer} from "mobx-react";
@inject('friend')
@observer
class Post extends Component{
    render() {
        const {
            friend
        } = this.props
        console.log(friend.friendPost.length,friend.activeId)
        return (
            <div>
                {friend.friendPost.map(item => <div>
                    <h4>{item.title}</h4>
                    <p>{item.content}</p>
                </div>)}
            </div>
        );
    }
}
export default Post


规范化

// store/post.js
import {
    observable,
    action
} from 'mobx'
const addForm = {
    title : '',
    content : '',
    friendId : '',
}
class Post {
    @observable addForm = {
        ...addForm
    }
    @observable list = [
        {
            title:'hello ryan',
            content: 'hello ryan post 1',
            id:1,
            friendId:1
        },
        {
            title:'hello ryan 1',
            content: 'hello ryan post 2',
            id:2,
            friendId:1
        },
        {
            title:'hello ryan 2',
            content: 'hello ryan post 3',
            id:3,
            friendId:1
        }
    ]
    @action
    handleAdd(){
        this.list.push(...this.addForm)
    }
    @action
    clear(){
        this.addForm = {
            ...addForm
        }
    }
}
const post = new Post()
export default post

//view/action/index.js

import React,{Component}from 'react'
import {inject, observer} from "mobx-react";
import {
    observable
} from 'mobx'
@inject('post')
@observer
class Action extends Component{
    render() {
        const {
            post
        } = this.props
        return (
            <div>
                <div>
                    <input placeholder='title' value={post.addForm.title} onChange={(e) => post.addForm.title = e.target.value }/>
                </div>
                <div>
                    <input placeholder='content' value={post.addForm.content} onChange={(e) => post.addForm.content = e.target.value }/>
                </div>
                <div>
                    <input type='number' placeholder='friendId' value={post.addForm.friendId} onChange={(e) => post.addForm.friendId = parseInt(e.target.value) }/>
                </div>
                <button onClick={(e) => {
                    // post.list.push()
                    post.handleAdd()
                }}>add</button>
            </div>
        );
    }
    componentWillUnMount(){
        post.clear()
    }
}
export default Action



常用组件库ant-design

  1. 页面初始化,先显示loading组件,显示的时候请求初始化数据,将数据存到全局对象中,然后卸载掉root,再将App组件组件挂载到root上

import React, { useReducer } from 'react'
import { render, unmountComponentAtNode } from 'react-dom'
import Provider from 'react-redux/es/components/Provider'
import { store } from './store'
import App from './App'
import 'antd/dist/antd.css'
import {
  getInitData
} from './api/auth'
let root = document.getElementById('root')
class Init extends React.Component {
  render () {
    return (
      <div>
        loading...
      </div>
    )
  }
  renderApp (initData) {
    unmountComponentAtNode(root)
    Object.assign(global, {
      initData
    })
    render(
      <Provider store={store}>
        <App />
      </Provider>, root
    )
  }
  componentDidMount () {
    getInitData().then(initData => {
      this.renderApp(initData)
    })
  }
}
render(<Init />, root)


2.封装网络请求


import request from 'axios'
request.interceptors.request.use(req => {
  console.group(req.method, ':', req.url)
  return req
})
request.interceptors.response.use(res => {
  if (res.data.status === '401') {
    location.href = '/login'
    return
  }
  return res
})
const getInitialData = params => request.get('/getInitialData', { params })


<></>相当于占位符,Header组件不用最外层的标签进行包裹,该组件内部的子元素直接套在该组件下


import React, { Component } from 'react'
import {
  Popover,
  Button
} from 'antd'
import {history} from '../../config'
const content = (
  <div>
    <p to='/logout' onClick={e => {
      history.push('/logout')
    }}>退出</p>
  </div>
);
class Header extends Component {
  render () {
    return (
         <>
        <div className='app__header__logo'>React学习</div>
        <div className='app__header__ad'>学而时习之</div>
        <div className='app__header__action'>
          <Popover content={content} title="Title" trigger="click">
            <span>ryan</span>
          </Popover>
        </div>
      </>
    )
  }
}
export default Header


封装路由历史,首先下载history包


import axios from 'axios'
import { createHashHistory } from 'history'
export const request = axios
request.defaults.baseURL = 'http://127.0.0.1:7777'
// request.defaults.withCredentials = true
request.interceptors.request.use((req) => {
  if (PRODUCTION) {
    console.log(req.method, ':', req.url)
  }
  return req
})
request.interceptors.response.use((res) => {
  console.log(res)
  console.group(res.config.method,res.config.url,res.status)
  console.log(res.data)
  console.groupEnd()
  return res.data
})
export const history = createHashHistory()


然后导入到路由组件中


import {Router, Route, Link } from "react-router";
import React from 'react'
import {history} from './config'
import Header from './views/header'
import Sider from './views/sider'
import './index.css'
function App() {
  return (
    <Router history={history}>
      <div className='app-content'>
        <div className='app-header'>
          <Header/>
        </div>
        <div className='app-body'>
          <div className='app-body__sider'>
            <Sider/>
          </div>
          <div className='app-body__content'>
            <Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
            <Route path="/topics" component={Topics} />
          </div>
        </div>
      </div>
    </Router>
  )
}
function Home() {
  return <h2>Home</h2>;
}
function About() {
  return <h2>About</h2>;
}
function Topics() {
  return <h2>Topics</h2>;
}
function Topic({ match }) {
  return <h3>Requested Param: {match.params.id}</h3>;
}
export default App


点击退出跳转到上一个页面


import React, { Component } from 'react'
import {
  Popover,
  Button
} from 'antd'
import {history} from '../../config'
const content = (
  <div>
    <p to='/logout' onClick={e => {
      history.push('/logout')
    }}>退出</p>
  </div>
);
class Header extends Component {
  render () {
    return (
      <>
        <div className='app__header__logo'>React学习</div>
        <div className='app__header__ad'>学而时习之</div>
        <div className='app__header__action'>
          <Popover content={content} title="Title" trigger="click">
            <span>ryan</span>
          </Popover>
        </div>
      </>
    )
  }
}
export default Header


React-Router原理 --React生态

class是一个类,虚拟dom通过给类名加一个标签<类名/>将这个类实例化了

Router和Route组件源码解析


import React from "react";
import PropTypes from 'prop-types'
class Router extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            hash: window.location.hash
        }
    }
    static childContextTypes = {
        hash: PropTypes.string,
    }
    getHash() {
        let url = window.location.hash.replace('#', '')
        return url
    }
    getChildContext() {
        return {
            hash: this.getHash()
        }
    }
    componentDidMount() {
        window.onhashchange = () => {//页面hash变化了通过window.location.hash可以捕捉到最新的hash
            //当hash值变化之后会引发重新渲染
            this.setState({
                hash: this.getHash()
            })
        }
    }
    render() {
        return (
            <>
                {this.props.children}
            </>
        );
    }
}
class Route extends React.Component {
    static contextTypes = {
        hash: PropTypes.string
    }
    render() {
        const {
            path,
            component
        } = this.props
        let instance = null
        const {
            hash
        } = this.context
        if (path === hash) {//实例化这个类            参数2:该组件的属性,如{name:a,age:3},参数3:子组件
            instance = React.createElement(component, null, null)
        }
        return (
            <>
                {instance}
            </>
        );
    }
}
class AA extends React.Component {
    render() {
        return (
            <div>
                aa
            </div>
        );
    }
}
class BB extends React.Component {
    render() {
        return (
            <div>
                bb
            </div>
        );
    }
}
function App() {
    return (
        <div className="App">
            <Router >
                <header className="App-header">
                    <div>header</div>
                    <Route path='/aa' component={AA} />
                    <Route path='/bb' component={BB} />
                </header>
            </Router>
        </div>
    );
}
export default App


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值