react学习

最近跟着教程,简单了解了一下react

搭建react环境

1.安装node,npm

npx create-react-app my-app
cd my-app
npm start

插件Simple React Snippets

快捷 imrc , cc

目录介绍

public:是放公共文件的

  • mainifest.json:移动端配置文件,这个会在以后的课程中详细讲解。

src放自己编写的文件

  • index.js: 入口文件。

  • serviceWorker.js: 这个是用于写移动端开发的,PWA必须用到这个文件,有了这个文件,就相当于有了离线浏览的功能。


组件引入

1.在index.js文件引入

React,ReactDOM是必要的

App就是我们传说中的react组件了(组件化开发)

调用ReactDOM.render()方法把你的组件挂载到dom节点上

ReactDOM.render(组件,dom节点)

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

ReactDOM.render(<App />,document.getElementById('root'))

2.编写App.js组件

react的组件是写成类的样子

类里有个render()方法写html结构

在示例中这种类似 XML 的写法被称为 JSX

import React, { Component } from 'react'
//相当于 import React from 'react'
//const Component = React.Component 解构赋值

class App extends Component {
  render () {
    return (
      <div>
        Hello React!
      </div>
    )
  }
}

export default App;

npm start 就可以看到页面了


JSX

JSX就是Javascript和XML结合的一种格式。

上述app.js组件里 render() return的就是jsx

可以理解为js和html混用

1.语法

当遇到<,JSX就当作HTML解析,遇到{就当JavaScript解析.

ReactDOM.render(
    <div>
      <h1>{i == 1 ? 'True!' : 'False'}</h1>
    </div>
    ,
    document.getElementById('example')
);

jsx不能使用if else,但可以使用三目运算符

jsx推荐使用内联样式,在指定元素数字后自动添加px

注释写在{/* 注释 */}中 ,vscode快捷键ctrl+/

var myStyle = {
    fontSize: 100,
    color: '#FF0000'
};
ReactDOM.render(
    <h1 style = {myStyle}>菜鸟教程
     {/* 注释 */}
    </h1>,
    document.getElementById('example')
);

JSX 允许在模板中插入数组,数组会自动展开所有成员:

var arr = [
  <h1>菜鸟教程</h1>,
  <h2>学的不仅是技术,更是梦想!</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

2.引入css文件用classname

a.在组件里引入css文件

import '地址'

b.使用时class替换成className

3.将字符串以html进行解析

class Xiaojiejie extends Component{
    constructor(props){
        super(props)
        this.state = {
            content:'<h1>标题<h1>'
        }
    }
    render(){
        return(
                <div>        
                    <div dangerouslySetInnerHTML={{__html:this.state.content}}></div>
                </div>
        )
    }
   
}

export default Xiaojiejie

在显示时,将内容写入__html对象中

第一{}代表jsx语法开始,第二个是代表dangerouslySetInnerHTML接收的是一个对象键值对

dangerouslySetInnerHTML={{__html:this.state.content}}

3.label标签

label标签的for 和 input 的id 一般共同使用,是对应关系

但是在jsx里for要用htmlFor代替

<div>
    <label htmlFor="jspang">加入服务:</label>
    <input id="jspang"  value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
</div>

一个例子

1.写一个组件Xiaojiejie.js

1.在constructor里定义data

2.事件绑定

注意: a.需要用bind改变this指向 b.在react里用this.setState(变量:改变值)改变变量

react里面禁止直接操作state!!

import React,{Component} from 'react'

class Xiaojiejie extends Component{
    constructor(props){
        super(props)
        this.state = {
            inputValue: '',
            list:['111','222']
        }
    }
    render(){
        return(
                <div>
                    <div><input value = {this.state.inputValue} onChange={this.inputChange.bind(this)} /><button onClick={this.addList.bind(this)}>增加服务</button></div>
                    <ul>
                        {
                            this.state.list.map((item,index)=>{
                                return (
                                <li key={item+index}
                                    onClick = {this.deleteItem.bind(this,index)}
                                >{item}</li>
                                )
                            })
                        }
                    </ul>
                </div>
        )
    }
    inputChange(e){
        //如果不绑定this,this是undefined,绑定后指向的是这个类的s(?)
        this.setState({
            inputValue:e.target.value
        })
    }
    addList(){
        this.setState({
            list:[...this.state.list,this.state.inputValue]
        })
    } 
    deleteItem(index){
        let list = this.state.list
        list.splice(index,1)
        this.setState({
            list:list
        })
        //不要直接修改state的数据,后续性能优化会有问题
        //this.state.list.splice(index,1)
    }   
}

export default Xiaojiejie

我们需要最外用一个div进行包裹

如果不想用div可以用Fragment代替

但是要引入

import React,{Compnent,Fragment} from 'react'

2.在index.js引入并且使用

组件拆分

我们想将上述例子的每一项li作为组件拆出来

新建组件xiaojiejieitem.js

import React, { Component } from 'react';
class XiaojiejieItem extends Component {
    state = {  }
    render() { 
        return ( <div>选项1</div> );
    }
}
 
export default XiaojiejieItem;

在Xiaojiejie的组件里导入并使用

class Xiaojiejie extends Component{
	...
    render(){
        return(
                <div>
                    <div><input value = {this.state.inputValue} onChange={this.inputChange.bind(this)} /><button onClick={this.addList.bind(this)}>增加服务</button></div>
                    <ul>
                        {
                            this.state.list.map((item,index)=>{
                                return (
                                    <div>
                                        <XiaojiejieItem key={index+item}></XiaojiejieItem>
                                    </div>
                                )
                            })
                        }
                    </ul>
                    <div dangerouslySetInnerHTML={{__html:this.state.content}}></div>
                </div>
        )
    }
    
}


传值

不同组件的通信

父子组件传值

父组件传值给子组件依靠属性传递

Xiaojiejie.js

<XiaojiejieItem content={item}></XiaojiejieItem>

XiaojiejieItem.js

import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc

    render() { 
        return ( 
            <div>{this.props.content}</div>
         );
    }
}

export default XiaojiejieItem;

子组件不能直接操作父组件的数据,只能通过父组件的方法进行修改

想实现点击选项删除该选项

父组件需要传递 1.index 2.删除的方法(传递的方法也要绑this)

Xiaojiejie.js

 <XiaojiejieItem 
                                    key={index+item}  
                                    content={item}
                                    index={index}
                                    deleteItem={this.deleteItem.bind(this)} />

子组件新写一个方法调用传递的方法进行响应

import React, { Component } from 'react';
class XiaojiejieItem extends Component {
    constructor(props){
        super(props)
        //在constructor里绑定性能更好
        this.handleClick = this.handleClick.bind(this)
    }
    render() { 
        return ( 
        <div onClick={this.handleClick}>{this.props.content}</div> );
    }
    handleClick(){
        this.props.deleteItem(this.props.index)
    }
}
 
export default XiaojiejieItem;

PropType对接收传递值的类型进行规定

XiaojiejieItem.js

1.导入 2.使用

import PropTypes from 'prop-types'
class XiaojiejieItem extends Component{..}
XiaojiejieItem.propTypes = {
    content: PropTypes.string,
    index: PropTypes.number,
    deleteItem: PropTypes.func

}
...

这样如果传值类型不对就会报错

isRequired关键字了,它表示必须进行传递,如果不传递就报错。

content: PropTypes.string.isRequired

defalutProps就可以实现默认值的功能

XiaojiejieItem.defaultProps = {
    content:'1111'
}

ref的使用

ref是用来绑定dom的

使用

如下用ref绑定了input,在方法里用this.input 调用

<input 
    value={this.state.inputValue} 
    onChange={this.inputChange.bind(this)}
    //关键代码——----------start
    ref={(input)=>{this.input=input}}
    //关键代码------------end
    />
inputChange(){
    this.setState({
        inputValue:this.input.value
    })
}

首先要知道this.setState()这个函数是异步的,在这个函数和后面使用ref操作dom,就会this.setState()还没执行完,后面的操作就执行了

但是this.setState()的第二个函数是一个回调函数,我们可以把ref的操作放在这里

例子: 用ref绑定了ul, addList方法中使用

 <ul ref={(ul)=>{this.ul = ul}}>
                        {
                            this.state.list.map((item,index)=>{
                                return (
                                    <XiaojiejieItem 
                                    key={index+item}  
                                    content={item}
                                    index={index}
                                    deleteItem={this.deleteItem.bind(this)} />
                                )
                            })
                        }
                    </ul>
addList(){
        this.setState({
            list:[...this.state.list,this.state.inputValue],
            inputValue: '',
        },()=>{
            console.log('对的'+ this.ul.querySelectorAll('div').length)
        })
        console.log('错的'+ this.ul.querySelectorAll('div').length)
    } 

生命周期

  1. Initialization:初始化阶段。
  2. Mounting: 挂在阶段。
  3. Updation: 更新阶段。
  4. Unmounting: 销毁阶段

Mounting阶段

Mounting阶段叫挂载阶段,伴随着整个虚拟DOM的生成,它里边有三个小的生命周期函数,分别是:

  1. componentWillMount : 在组件即将被挂载到页面的时刻执行。

  2. render : 页面state或props发生变化时执行。

  3. componentDidMount : 组件挂载完成时被执行。

    在这个周期请求数据

componentWillMount(){
    console.log('componentWillMount----组件将要挂载到页面的时刻')
}
componentDidMount(){
    console.log('componentDidMount----组件挂载完成的时刻执行')
}
render(){
    console.log('render---组件挂载中.......')
}

componentWillMountcomponentDidMount这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有state和props变化就会执行

Updation阶段

Updation阶段,也就是组件发生改变的更新阶段,这是React生命周期中比较复杂的一部分,它有两个基本部分组成,一个是props属性改变,一个是state状态改变。

1.shouldComponentUpdate函数

shouldComponentUpdate函数会在组件更新之前,自动被执行。要求返回一个布尔类型的结果,必须有返回值。返回值true/false。就是返回true,就同意组件更新;返回false,就反对组件更新。

shouldComponentUpdate(){
    console.log('shouldComponentUpdate---组件发生改变前执行')
    return true
}

解决子组件频繁无用渲染render 的性能问题

shouldComponentUpdate有两个参数:

  • nextProps:变化后的属性;
  • nextState:变化后的状态;

在子组件中加入

shouldComponentUpdate (nextProps, nextState) {
        if (nextProps.content !== this.props.content) {
            return true
        } else {
            return false
        }
    }

2.componentWillUpdate函数

componentWillUpdateshouldComponenUpdate之后被执行,组件更新之前执行。

//shouldComponentUpdate返回true才会被执行。
componentWillUpdate(){
    console.log('componentWillUpdate---组件更新前,shouldComponentUpdate函数之后执行')
}

3.componentDidUpdate

componentDidUpdate在组件更新之后执行,它是组件更新的最后一个环节。

componentDidUpdate(){
    console.log('componentDidUpdate----组件更新之后执行')
}

几个函数的执行顺序

1-shouldComponentUpdate---组件发生改变前执行
2-componentWillUpdate---组件更新前,shouldComponentUpdate函数之后执行
3-render----开始挂载渲染
4-componentDidUpdate----组件更新之后执行

4.compoenentWillReceiveProps

子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行。

unmount阶段

componentWillUnmount函数

组件从页面中删除的时候执行

一个例子

用react做一个css的动画

主要是再熟悉一下react吧。。

点击按钮实现元素的出现和隐藏

import React, { Component } from 'react';
class Sunwukong extends Component {
    render () {
        return (
            <div>
                <div className={this.state.isShow ? 'show' : 'hide'}>孙悟空</div>
                <button onClick={this.toToggle}>点我</button>
            </div>
        );
    }
    constructor(props) {
        super(props)
        this.state = {
            isShow: true
        }
        this.toToggle = this.toToggle.bind(this)
    }
    toToggle () {
        this.setState({
            isShow: this.state.isShow ? false : true
        })
    }
}

export default Sunwukong;

在主组件引入的css文件写

.show{
    opacity: 1 ;
    transition: all 1.5s ease-in;
}
.hide{
    opacity: 0 ;
    transition: all 1.5s ease-in;
}

理论:单项数据流

子组件不能直接操作父组件的数据,只能通过父组件的方法进行修改

可以理解父组件将值传递给子组件时,子组件不能直接修改,所有数据是单向的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值