React基础

一、基本使用

JSX基本使用

state就是vue里的data:

 constructor(props) {
        super(props)
        this.state = {
            name: '双越',
            imgUrl: 'https://img1.mukewang.com/5a9jpg',
            flag: true
        }
    }
 // // 获取变量 插值
         const pElem = <p>{this.state.name}</p>
        return pElem
React在{ }里用JS表达式  但在vue都是使用{{ }}来包裹
        // // 表达式
         const exprElem = <p>{this.state.flag ? 'yes' : 'no'}</p>
         return exprElem
写动态属性统统用{ }包裹就行了 vue里面用的是v-bind:
非动态属性和vue一样 正常写就行了
        // // 子元素
         const imgElem = <div>
             <p>我的头像</p>
             <img src="xxxx.png"/>
             <img src={this.state.imgUrl}/>
         </div>
         return imgElem
React class要写成className vue还是可以写class
   // // class
         const classElem = <p className="title">设置 css class</p>
         return classElem
设置style使用{ } 在vue中则是使用:style="styleData"
 // // style
        /const styleData = { fontSize: '30px',  color: 'blue' }
         const styleElem = <p style={styleData}>设置 style</p>
        // // 内联写法,注意 {{ 和 }} 和vue的{{ }}可不一样!
const styleElem = <p style={{ fontSize:'30px',color:'blue' }}>设置style</p>
    return styleElem
原生html就比较麻烦:
        // 原生 html
        const rawHtml = '<span>富文本内容<i>斜体</i><b>加粗</b></span>'
        const rawHtmlData = {
            __html: rawHtml // 注意,必须是这种格式
        }
        const rawHtmlElem = <div>
            <p dangerouslySetInnerHTML={rawHtmlData}></p>
            <p>{rawHtml}</p>
        </div>
        return rawHtmlElem
加载组件是通过JSX语法 <组件名/>的形式 当然 也同样需要引入啦!这点和vue一样!不过vue组件后还需要component里面注册一下 react比较方便 直接用就行了!
        // // 加载组件
         const componentElem = <div>
             <p>JSX 中加载一个组件</p>
             <hr/>
             <List/>
         </div>
         return componentElem
导出部分也不同 React的导出只有一句话export default JSXBaseDemo 而Vue导出一堆东西

JSX条件判断

react的条件判断非常简单粗暴 vue用的是v-if v-else-if v-else 在react直接if-else
     // // if else
         if (this.state.theme === 'black') {
             return blackBtn
         } else {
             return whiteBtn
         }
三元运算符
        // // 三元运算符
         return <div>
          { this.state.theme === 'black' ? blackBtn : whiteBtn }
         </div>
&&
        return <div>
            { this.state.theme === 'black' && blackBtn }
        </div>
总的来说 React的语法非常接近原生JS的语法
JSX列表渲染
搞定map 和 key就够用了
map最终返回的是一个新的数组 react里面的key和vue的类似
import React from 'react'

class ListDemo extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            list: [
                {
                    id: 'id-1',
                    title: '标题1'
                },
                {
                    id: 'id-2',
                    title: '标题2'
                },
                {
                    id: 'id-3',
                    title: '标题3'
                }
            ]
        }
    }
    render() {
        return <ul>
             this.state.list.map(
                (item, index) => {
    // 这里的 key 和 Vue 的 key 类似,必填,不能是 index 或 random
                  return <li key={item.id}>
               index {index}; id {item.id}; title {item.title}
                   </li>
                    }
                )
            }
        </ul>
    }
}

export default ListDemo

*事件

重点终于来了!
首先要记住:在React中绑定事件 事件都写为onXxxxx的形式 在vue中都是@click

1.bind this

import React from 'react'

class EventDemo extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'zhangsan',
            list: [
                {
                    id: 'id-1',
                    title: '标题1'
                },
                {
                    id: 'id-2',
                    title: '标题2'
                },
                {
                    id: 'id-3',
                    title: '标题3'
                }
            ]
        }

        // 修改方法的 this 指向
        this.clickHandler1 = this.clickHandler1.bind(this)
    }
在react中,this默认是undefined 
有两种解决方法:
法一:在调用方法时bind this 使函数指向当前对象  为了提升性能最好把bind this写在constructor里更好
        // // this - 使用 bind
         return <p onClick={this.clickHandler1}>
             {this.state.name}
         </p>
 clickHandler1() {
        // console.log('this....', this) // this 默认是 undefined
        this.setState({
            name: 'lisi'
        })
    }
法二:用静态方法写 this就始终指向当前实例 (也就是箭头函数呢!!)
  // // this - 使用静态方法
         return <p onClick={this.clickHandler2}>
             {this.state.name}
         </p>
// 静态方法,this 指向当前实例
    clickHandler2 = () => {
        this.setState({
            name: 'lisi'
        })
    }

2.event

      // // event
      return <a href="https://imooc.com/" onClick={this.clickHandler3}>
          click me
        </a>
// 获取 event
    clickHandler3 = (event) => {
      event.preventDefault() // 阻止默认行为
      event.stopPropagation() // 阻止冒泡
      console.log('target', event.target) // 指向当前元素,即当前元素触发
      console.log('current target', event.currentTarget) // 指向当前元素,假象!!!

  // 注意,event 其实是 React 封装的。可以看 __proto__.constructor 是 SyntheticEvent 组合事件
        console.log('event', event) // 不是原生的 Event ,原生的 MouseEvent
        console.log('event.__proto__.constructor', event.__proto__.constructor)

        // 原生 event 如下。其 __proto__.constructor 是 MouseEvent
        console.log('nativeEvent', event.nativeEvent)
        console.log('nativeEvent target', event.nativeEvent.target)  // 指向当前元素,即当前元素触发
        console.log('nativeEvent current target', event.nativeEvent.currentTarget) // 指向 document !!!

        // 1. event 是 SyntheticEvent ,模拟出来 DOM 事件所有能力
        // 2. event.nativeEvent 是原生事件对象
        // 3. 所有的事件,都被挂载到 document 上
        // 4. 和 DOM 事件不一样,和 Vue 事件也不一样
    }
自我总结:
在事件处理程序不传入参数的时候 默认参数就是event 这点是共通的
但在react中的event是被封装过的SyntheticEvent(组合事件)这个组合事件模拟出来了DOM事件的所有能力 而vue中则是原生event
比如点击事件 react的点击事件原型是SyntheticEvent  vue中的原型是MouseEvent
我们可以通过nativeEvent才能获取原生事件 可这个原生事件的触发target是当前元素 
绑定target是document
这点也和vue不同,vue中的触发事件和绑定事件相同 evnet被挂载到当前元素 和DOM一样
而react中的原生事件都被挂载到document上 挂栽在当前元素上的是假event 是SyntheticEvent

3.传递参数

如果给事件传递了参数,事件处理程序会自动在最后追加一个参数event
 // 传递参数 - 用 bind(this, a, b)
return <ul>{this.state.list.map((item, index) => {
return <li key={item.id} onClick={this.clickHandler4.bind(this,item.id,item.title)}>
index {index}; title {item.title}
            </li>
        })}</ul>
// 传递参数
    clickHandler4(id, title, event) {
      console.log(id, title)
      console.log('event', event) // 最后追加一个参数,即可接收 event
    }

表单

表单中的最大重点是受控组件
我们在vue中都用v-model 可react没有这种功能 只能自己实现
受控组件就相当于咱们自己实现的v-model
受控指的就是 我们的input的值受state控制了
/ // 受控组件(非受控组件,后面再讲)
        return <div>
            <p>{this.state.name}</p>
           <label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */}
           <input id="inputName" value={this.state.name} onChange={this.onInputChange}/>
         </div>
 onInputChange = (e) => {
        this.setState({
            name: e.target.value
        })
    }
剩下的textarea  select checkbox 就用完整代码了
import React from 'react'

class FormDemo extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: '双越',
            info: '个人信息',
            city: 'beijing',
            flag: true,
            gender: 'male'
        }
    }
    render() {

        // // 受控组件(非受控组件,后面再讲)
        // return <div>
        //     <p>{this.state.name}</p>
        //     <label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */}
        //     <input id="inputName" value={this.state.name} onChange={this.onInputChange}/>
        // </div>

        // textarea - 使用 value
        return <div>
            <textarea value={this.state.info} onChange={this.onTextareaChange}/>
            <p>{this.state.info}</p>
        </div>

        // // select - 使用 value
        // return <div>
        //     <select value={this.state.city} onChange={this.onSelectChange}>
        //         <option value="beijing">北京</option>
        //         <option value="shanghai">上海</option>
        //         <option value="shenzhen">深圳</option>
        //     </select>
        //     <p>{this.state.city}</p>
        // </div>

        // // checkbox
        // return <div>
        //     <input type="checkbox" checked={this.state.flag} onChange={this.onCheckboxChange}/>
        //     <p>{this.state.flag.toString()}</p>
        // </div>

        // // radio
        // return <div>
        //     male <input type="radio" name="gender" value="male" checked={this.state.gender === 'male'} onChange={this.onRadioChange}/>
        //     female <input type="radio" name="gender" value="female" checked={this.state.gender === 'female'} onChange={this.onRadioChange}/>
        //     <p>{this.state.gender}</p>
        // </div>

        // 非受控组件 - 后面再讲
    }
    onInputChange = (e) => {
        this.setState({
            name: e.target.value
        })
    }
    onTextareaChange = (e) => {
        this.setState({
            info: e.target.value
        })
    }
    onSelectChange = (e) => {
        this.setState({
            city: e.target.value
        })
    }
    onCheckboxChange = () => {
        this.setState({
            flag: !this.state.flag
        })
    }
    onRadioChange = (e) => {
        this.setState({
            gender: e.target.value
        })
    }
}

export default FormDemo

Copyright © 2018 imooc.com All Rights Reserved | 京ICP备 12003892号-11 简体中文×
拖拽到此处
图片将完成下载


二、父子组件通讯

又使用todolist来演示
父组件:
lass TodoListDemo extends React.Component {
    constructor(props) {
        super(props)
        // 状态(数据)提升
        this.state = {
            list: [
                {
                    id: 'id-1',
                    title: '标题1'
                },
                {
                    id: 'id-2',
                    title: '标题2'
                },
                {
                    id: 'id-3',
                    title: '标题3'
                }
            ],
            footerInfo: '底部文字'
        }
    }
    render() {
        return <div>
            <Input submitTitle={this.onSubmitTitle}/>
                        //向input传入方法
            <List list={this.state.list}/>
                        //向List传入this.state.list值
           
        </div>
    }
    onSubmitTitle = (title) => {
        this.setState({
            list: this.state.list.concat({
                id: `id-${Date.now()}`,
                title
            })
        })
    }
}

export default TodoListDemo
input:
class Input extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            title: ''
        }
    }
    render() {
        return <div>
            <input value={this.state.title} onChange={this.onTitleChange}/>
            <button onClick={this.onSubmit}>提交</button>
        </div>
    }
    onTitleChange = (e) => {
        this.setState({
            title: e.target.value
        })
    }
    onSubmit = () => {
                //从props调用父组件传过来的方法
        const { submitTitle } = this.props.submitTitle
        submitTitle(this.state.title) // 'abc'

        this.setState({
            title: ''
        })
    }
}

list:
class List extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
                //调用父组件传来的值
        const { list } = this.props.list

        return <ul>{list.map((item, index) => {
            return <li key={item.id}>
                <span>{item.title}</span>
            </li>
        })}</ul>
    }
}

三、**setState**

不可变值

第一,state 要在构造函数中定义
第二、不要直接修改state 它使用的是不可变值 只能使用setState进行修改
第三、如果是数组 不能直接对 this.state.list 进行 push pop splice 等,这样违反不可变值
可以看出来 这里使用的函数都是返回一个新数组 而不改变原数组
相当于做了一个副本 
 const list5Copy = this.state.list5.slice()
list5Copy.splice(2, 0, 'a') // 中间插入/删除

this.setState({
//     list1: this.state.list1.concat(100), // 追加
//     list2: [...this.state.list2, 100], // 追加
//     list3: this.state.list3.slice(0, 3), // 截取
//     list4: this.state.list4.filter(item => item > 100), // 筛选
//     list5: list5Copy // 其他操作
// })
第四、如果是对象  同样 注意,不能直接对 this.state.obj 进行属性设置,这样违反不可变值
 this.setState({
     obj1: Object.assign({}, this.state.obj1, {a: 100}),
     obj2: {...this.state.obj2, a: 100}
 })
// // 
可能是异步更新
直接用setState是异步的
       this.setState({
             count: this.state.count + 1
         }, () => {
        //     // 联想 Vue $nextTick - DOM
             console.log('count by callback', this.state.count) 
           // 回调函数中可以拿到最新的 state
         })
         console.log('count', this.state.count) // 异步的,拿不到最新值
在setTimeout中是同步的
// // setTimeout 中 setState 是同步的
       / setTimeout(() => {
             this.setState({
                 count: this.state.count + 1
             })
             console.log('count in setTimeout', this.state.count)
         }, 0)
自己定义的 DOM 事件,setState 是同步的
      bodyClickHandler = () => {
        this.setState({
             count: this.state.count + 1
         })
         console.log('count in body event', this.state.count)
     }



// componentDidMount() {
  
    //     document.body.addEventListener('click', this.bodyClickHandler)
    // }
    // componentWillUnmount() {
    //     // 及时销毁自定义 DOM 事件
    //     document.body.removeEventListener('click', this.bodyClickHandler)
    //     // clearTimeout
    // }

可能会合并

因为异步更新 只在传入对象的情况下才合并
// // 传入对象,会被合并(类似 Object.assign )。执行结果只一次 +1
         this.setState({
             count: this.state.count + 1
         })
         this.setState({
             count: this.state.count + 1
         })
         this.setState({
             count: this.state.count + 1
         })
        
传入函数则不会被合并
// 传入函数,不会被合并。执行结果是 +3
        this.setState((prevState, props) => {
            return {
                count: prevState.count + 1
            }
        })
        this.setState((prevState, props) => {
            return {
                count: prevState.count + 1
            }
        })
        this.setState((prevState, props) => {
            return {
                count: prevState.count + 1
            }
        })
    }

四、组件生命周期



可以和vue的结合着看
父子组件生命周期和vue一样

五、React高级特性(一)

函数组件
非受控组件
Portals
context
异步组件
性能优化
高阶组件HOC
Render Props

函数组件

相当于把一个简单的class组件写成函数形式

  • 纯函数 输入props 输出JSX
  • 没有实例 没有生命周期 没有state
  • 不能扩展其他方法

非受控组件

之前讲过受控组件,简单回顾一下:
/ // 受控组件(非受控组件,后面再讲)
        return <div>
            <p>{this.state.name}</p>
           <label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */}
           <input id="inputName" value={this.state.name} onChange={this.onInputChange}/>
         </div>
非受控组件
import React from 'react'

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: '双越',
            flag: true,
        }
        this.nameInputRef = React.createRef() // 创建 ref
        this.fileInputRef = React.createRef()
    }
    render() {
        // // input defaultValue
         return <div>
             {/* 使用 defaultValue 而不是 value ,使用 ref */}
                          //没有定义onChange事件 所以state不会改变
             <input defaultValue={this.state.name} ref={this.nameInputRef}/>
             {/* state 并不会随着改变 */}
             <span>state.name: {this.state.name}</span>
             <br/>
             <button onClick={this.alertName}>alert name</button>
         </div>

        // // checkbox defaultChecked
         return <div>
             <input
                 type="checkbox"
                 defaultChecked={this.state.flag}
             />
         </div>

        // 上传文件 拿到文件名
        return <div>
            <input type="file" ref={this.fileInputRef}/>
            <button onClick={this.alertFile}>alert file</button>
        </div>

    }
    alertName = () => {
        const elem = this.nameInputRef.current // 通过 ref 获取 DOM 节点
        alert(elem.value) // 不是 this.state.name
    }
    alertFile = () => {
        const elem = this.fileInputRef.current // 通过 ref 获取 DOM 节点
        alert(elem.files[0].name)
    }
}

export default App
说白了 input值怎么变化 跟组件无关 
我们只是把state的值拿过来做一个default而已
想要拿到里面的值 就需要通过ref来获取DOM节点
必须手动操作DOM元素,setState实现不了 比如文件上传<input type="file>

要注意react里使用ref的方法和VUE不同:
首先要创建ref:
this.nameInputRef = React.createRef() // 创建 ref
然后设置在标签上:
<input defaultValue={this.state.name} ref={this.nameInputRef}/>
最后通过 ref 获取 DOM 节点:
const elem = this.nameInputRef.current // 通过 ref 获取 DOM 节点

Portals

传送门
组件默认会按照既定层次嵌套渲染 但某些情况,需要让组件渲染到父组件以外
这时候就需要Portals
import React from 'react'
import ReactDOM from 'react-dom'
import './style.css'

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
        }
    }
    render() {
        // // 正常渲染  其实应该把这个放在body最外层 但是正常渲染不行
         return <div className="modal">//在modal中position:fixed
            {this.props.children} {/* 类似于 vue slot */}
         </div>

        // 使用 Portals 渲染到 body 上。
        // fixed 元素要放在 body 上,有更好的浏览器兼容性。
        return ReactDOM.createPortal(
            <div className="modal">{this.props.children}</div>,
            document.body // 这里写DOM节点 就是自定义要渲染的地方
        )
    }
}

export default App
说白了 就是逃离父组件 应用场景为:
  • 父组件设置overflow:hidden
  • 父组件z-index值太小
  • fixed需要放在第一层

Context

公共信息(语言 主题)用props传递太繁琐 用redux小题大做 用context就刚刚好
import React from 'react'

// 创建 Context 填入默认值(任何一个 js 变量)
const ThemeContext = React.createContext('light')

// 底层组件 - 函数是组件
function ThemeLink (props) {
    // const theme = this.context // 会报错。函数式组件没有实例,即没有 this

    // 函数式组件可以使用 Consumer
    return <ThemeContext.Consumer>
        { value => <p>link's theme is {value}</p> }
    </ThemeContext.Consumer>
}

// 底层组件 - class 组件
class ThemedButton extends React.Component {
    // 指定 contextType 读取当前的 theme context。
    // static contextType = ThemeContext // 也可以用 ThemedButton.contextType = ThemeContext
    render() {
        const theme = this.context // React 会往上找到最近的 theme Provider,然后使用它的值。
        return <div>
            <p>button's theme is {theme}</p>
        </div>
    }
}
ThemedButton.contextType = ThemeContext // 指定 contextType 读取当前的 theme context。

// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar(props) {
    return (
        <div>
            <ThemedButton />
            <ThemeLink />
        </div>
    )
}
//最外层的组件 由它产生一些数据
class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            theme: 'light'
        }
    }
    render() {
        return <ThemeContext.Provider value={this.state.theme}>
            <Toolbar />
            <hr/>
            <button onClick={this.changeTheme}>change theme</button>
        </ThemeContext.Provider>
    }
    changeTheme = () => {
        this.setState({
            theme: this.state.theme === 'light' ? 'dark' : 'light'
        })
    }
}

export default App
主要是以下步骤
首先,通过React.createContext 创建一个Context
// 创建 Context 填入默认值(任何一个 js 变量)
const ThemeContext = React.createContext('light')
在最外层组件通过在<ThemeContext.Provider>标签里给context赋值:
  return <ThemeContext.Provider value={this.state.theme}>
在class类组件里:
使用ThemedButton.contextType = ThemeContext  设置子组件的contextType为父组件的context
也可以通过 静态属性static contextType = ThemeContext 的方法来设置
来读取父组件的context
// 底层组件 - class 组件
class ThemedButton extends React.Component {
    // 指定 contextType 读取当前的 theme context。
    // static contextType = ThemeContext 
// 也可以用 ThemedButton.contextType = ThemeContext
    render() {
        const theme = this.context 
// React 会往上找到最近的 theme Provider,然后使用它的值。
        return <div>
            <p>button's theme is {theme}</p>
        </div>
    }
}
ThemedButton.contextType = ThemeContext 
// 指定 contextType 读取当前的 theme context。
在函数组件里 通过<ThemeContext.Consumer>标签包裹 在标签里就可以使用context的内容了
// 底层组件 - 函数是组件
function ThemeLink (props) {
    // const theme = this.context // 会报错。函数式组件没有实例,即没有 this

    // 函数式组件可以使用 Consumer
    return <ThemeContext.Consumer>
        { value => <p>link's theme is {value}</p> }
    </ThemeContext.Consumer>
}

异步组件

和vue的异步组件差不多 vue是通过import( ) 
React使用 React.lazy 和 React.Suspense
React.lazy(() => import('./ContextDemo'))
<React.Suspense fallback={<div>Loading...</div>}> 表示 当加载中调用的函数
import React from 'react'

const ContextDemo = React.lazy(() => import('./ContextDemo'))

class App extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        return <div>
            <p>引入一个动态组件</p>
            <hr />
            <React.Suspense fallback={<div>Loading...</div>}>
                <ContextDemo/>
            </React.Suspense>
        </div>

        // 1. 强制刷新,可看到 loading (看不到就限制一下 chrome 网速)
        // 2. 看 network 的 js 加载
    }
}

export default App

六、React高级特性(二)

**性能优化

性能优化是大重点!!!!!

SUC




React 默认:
  • 父组件更新时,子组件无条件更新 因此SCU默认返回ture 
  • 但SCU不一定每次都用 需要的时候才优化
  • 必须配合“不可变值”一起使用 如果不适用不可变值,如果对list数组进行push,push后list就发生了改变,当在setState时,前后两个list值一样!SCU判断前后值时判断相等 返回false 就不会重新渲染了
  • (所以不可变值很重要 一定要保证原本的值不变!)
  • 但由于react没法约束开发者在setState中都遵循不可变值的原则,所以默认返回true,每次改变都渲染
// // 为了演示 SCU ,故意写的错误用法
         this.state.list.push({
             id: `id-${Date.now()}`,
             title
         })
         this.setState({
             list: this.state.list
         })
可使用_.isEqual做深度比较 但并不建议
    // 增加 shouldComponentUpdate
    shouldComponentUpdate(nextProps, nextState) {
        // _.isEqual 做对象或者数组的深度比较(一次性递归到底)耗费性能
        if (_.isEqual(nextProps.list, this.props.list)) {
            // 相等,则不重复渲染
            return false
        }
        return true // 不相等,则渲染
    }

PureComponent和memo

PureComponent可以在SCU中实现浅比较 但同样要配合不可变值
使用非常简单 就是在初始化组件的时候继承React.PureComponent
class List extends React.PureComponent
memo就是函数组件中的PureComponent

immutable.js

彻底拥抱“不可变值”
基于共享数据(不是深拷贝) 速度更好
但有一定学习成本

高阶组件

高阶组件就是用来做公共逻辑抽离的
在vue中我们只用mixin 但React不用mixin 而是用高阶组件HOC 和Render Props

import React from 'react'

// 高阶组件
const withMouse = (Component) => {
        //创建一个组件
    class withMou***ponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = { x: 0, y: 0 }
        }
             //定义方法
        handleMouseMove = (event) => {
            this.setState({
                x: event.clientX,
                y: event.clientY
            })
        }
  
        render() {
                      //写公共逻辑
            return (
         <div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}>
          {/* 1. 透传所有 props(VUE中用$props) 2. 增加 mouse 属性 */}
                    //这里的component就是传入的子组件 !!!!//
            <Component {...this.props} mouse={this.state}/>
                </div>
            )
        }
    }
    return withMou***ponent
}


//使用公共逻辑的函数子组件
const App = (props) => {
    const a = props.a
    const { x, y } = props.mouse // 解构赋值 接收 mouse 属性
    return (
        <div style={{ height: '500px' }}>
            <h1>The mouse position is ({x}, {y})</h1>
            <p>{a}</p>
        </div>
    )
}

export default withMouse(App) // 做一下封装 返回高阶函数
redux connect就是高阶组件
—————————————————————————————————————
补充知识点:

高阶函数

高阶函数,是一种特别的函数,接受的参数为函数,返回值也是函数。成立条件,二者兼一即可
可以看出来,高阶函数和闭包紧密关联!闭包就是一个内部函数
个人理解是,高阶函数中包含了闭包
常见的高阶函数有:
        a).定时器:setTimeout()/setInterval()
        b).Promise:Promise(()=>{})  then(value=>{},reason=>{})
        c).数组遍历相关的方法: forEach()/ filter()/ map()/ find()/ findindex()
        d).fn.bind() 本身是个函数,bind方法返回一个新的函数方法
        e).Form.create()()  create函数能够包装组件,生成另外一个组件的新功能函数 
        f).getFieldDecorator()()
——————————————————————————————————_
在高阶函数这个概念基础上,再来品味一下高阶组件

高阶组件:就是接受一个组件作为参数并返回一个新组件的函数 本质上它还是一个函数
也就是把子组件 当作一个参数 传入高阶组件这个函数里 在函数里对子组件这个那个 返回这个那个后的子组件

Render Props

和高阶组件类似 

高阶组件是 用函数去包裹子组件
而Render Props 是子组件去包裹render函数组件


import React from 'react'
import PropTypes from 'prop-types'
//高阶组件是写一个函数 这就是写一个类 
class Mouse extends React.Component {
    constructor(props) {
        super(props)
        this.state = { x: 0, y: 0 }
    }
  
    handleMouseMove = (event) => {
      this.setState({
        x: event.clientX,
        y: event.clientY
      })
    }
  
    render() {
      return (
        <div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}>
      {/* 将当前 state 作为 props ,传递给 render (render 是一个函数组件)*/}
            //高阶组件里这里写的是子组件
            {this.props.render(this.state)}
        </div>
      )
    }
}
//一个类型校验 规定必须接受一个render属性
Mouse.propTypes = {
    render: PropTypes.func.isRequired // 必须接收一个 render 属性,而且是函数
}


//这个APP组件 没有被包裹 所以可以直接接收外面传过来的参数//
const App = (props) => (
    <div style={{ height: '500px' }}>
        <p>{props.a}</p>
                //用APP组件来包裹父组件 给父组件Mouse传入render这个函数组件作为prop//
        <Mouse render={
            /* render 是一个函数组件 */
                        //在render里规定了APP组件如何渲染 显示什么内容//
            ({ x, y }) => <h1>The mouse position is ({x}, {y})</h1>
        }/>
        
    </div>
)

/**
 * 即,定义了 Mouse 组件,只有获取 x y 的能力。
 * 至于 Mouse 组件如何渲染,App 说了算,通过 render prop 的方式告诉 Mouse 。
 */

export default App
HOC:模式简单 但会增减组件层级
Render props:代码简洁

React-router

和vue差不多!

动态路由:
跳转路由

懒加载

全部评论

相关推荐

不愿透露姓名的神秘牛友
昨天 10:27
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-29 14:02
点赞 评论 收藏
分享
酷酷我灵儿帅:这去不去和线不线下面说实话没啥关系
点赞 评论 收藏
分享
08-05 14:00
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务