react基础爱记不记

虚拟DOM

render函数中返回的看似html的jsx语法模板会经过React.createElement()生成一个虚拟DOM,然后虚拟DOM再渲染真实DOM。

在虚拟dom进行比对的时候react提供了diff算法,以下关于diff算法的几个记点:

1、setState()修改数据就会触发虚拟dom比对,也就是运用diff算法,但连续的多次setState会被合并成一次setState,也就是只进行一次虚拟dom比对,这是一个性能优化。

2、虚拟dom比对时是同层级比对,如果第一层比对就不一样那么就不会再往下进行比对,react会将原来的dom全部销毁生成新的dom进行替换。这样做可能会有渲染dom的一些浪费,但同层比对会使diff算法性能高。

3、循环遍历的元素上要加key,且是稳定唯一的值,不要用index(因为不稳定),这样是为了进行比对时确定两个虚拟dom中对应的节点。

下面来看几张图分析一下

上图所示,先进行第一层比对R相同,再进行第二层,D和G不同,将D以及D下面的E、F销毁,重新创建G、E、F。

上图所示,列表元素中加了key值,在一系列的移动,移除,添加之后,D销毁,E添加,A、B移动,C不变。

参考文章

 

html文本不转义输出

<p dangerouslySetInnerHTML={{__html: '<h2>html输出</h2>'}}></p>

 

input数据响应

// state
constructor(props){
  super(props);
  this.state = {
    inputValue: 'hello Sam'
  }
}
{/* html */}
<label htmlFor="input">请输入</label>
<input id="input" type="text" value={this.state.inputValue} onChange={this.handleInputChange.bind(this)}/>
// handle
handleInputChange(e){
  this.setState({
    inputValue: e.target.value
  })
}

上面handleInputChange方法也可写成箭头函数 handleInputChange = e => {} ,还有一种推荐写法,将 this.handleInputChange = this.handleInputChange.bind(this) 写进constructor函数里。

 

数组增减(setState())

react中不允许直接改变state,需要改变数据都要使用setState()。下面看react中怎么改变数组,充分运用es6语法。

handleArray(index){
  // 数组后面新增newItem
  // this.setState({
  //   list: [...this.state.list, newItem]
  // })

  // 数组去除某项
  let arr = [...this.state.list];
  arr.splice(index, 1);
  this.setState({
    list: arr
  })
}

 

组件

父组件传递数据给子组件

跟vue一样,通过在子组件标签添加自定义属性的方式。

{/* 父组件 */}
<Child parentMsg={'hahalala'}></Child>
// 子组件
class Child extends Component{
    render(){
        return (
            <div>
                <h2>{this.props.parentMsg}</h2>
            </div>
        )
    }
}

子组件传递数据给父组件

实现方法跟上面差不多,就是给子组件标签加属性时传的是一个函数,然后子组件中通过this.props获得这个函数调用即可。

{/* 父组件 */}
<p>{this.state.childMsg}</p>
<Child fromChild={this.handleChildMsg.bind(this)}></Child>
// 父组件
handleChildMsg(str){
  this.setState({
    childMsg: str
  })
}
// 子组件
class Child extends Component{
    render(){
        return (
            <div>
                <h2 onClick={this.sendToParent.bind(this)}>hello</h2>
            </div>
        )
    }

    sendToParent(){
        this.props.fromChild('hello lala');
    }
}

props校验

// 引包
import PropTypes from 'prop-types';
 
// props校验
Child.propTypes = {
    prop1: PropTypes.string,    // 如果没传就不会检测,所以不会报错
    prop2: PropTypes.string.isRequired,     //如果没传,会报警告
    prop3: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),//可是字符串或者数字
    prop4: PropTypes.func,
    prop5: PropTypes.array
}

// 默认prop
Child.defaultProps = {
    prop1: 'hello world'
}

 

ref获取dom元素及setState异步

ref获取dom元素

{/* html */}
<input type="text" ref={el => {this.input = el}}/>

// 获取
this.input

和vue一样,在数据变化之后即可操作dom可能会有一些影响,因为此时虽然数据变化了,但还没渲染到页面上。在vue红vue给我们提供了$nextTick方法,而react中可以在setState函数中操作,因为setState实际是个异步函数。setState函数传入第二个参数,是一个回调函数,将dom操作写在回调函数里面。

setState中操作dom

{/* html */}
<input type="text" value={this.state.inputValue} ref={el => {this.input = el}}/>
// js
handleInput(){
    this.setState({
        inputValue: 'bbb'
    }, () => {            
        console.log(this.input.value)
    })
}

 

生命周期函数

生命周期函数是指在某一时刻组件会自动调用执行的函数。

constructor():本质上来说它也算声明周期,这是es6对类的定义里的默认函数,手动声明constructor时必须调用super方法,在constructor中如果要访问this.props需要传入props 。

componentWillMount():组件挂载之前,只调用一次,react17之后会被移除

render():相当重要,必须定义,创建虚拟dom,进行diff算法,更新dom树都在此进行。

componentDidMount():组件挂载完成后,只调用一次,此时可获取真实dom元素,推荐将ajax请求写在这里。

componentWillReceiveProps (nextProps):props发生变化以及父组件重新渲染时都会触发该生命周期,在该钩子内可以通过参数nextProps获取变化后的props参数,通过this.props访问之前的props。该生命周期内可以进行setState。React17后会被移除。(React v16.3后可以用新的周期 static getDerivedStateFromProps 代替)

shouldComponentUpdate(nextProps, nextState):是否重新渲染。组件挂载之后,每次调用setState后都会调用shouldComponentUpdate判断是否需要重新渲染组件。默认返回true,需要重新render。返回false则不触发渲染。在比较复杂的应用里,有一些数据的改变并不影响界面展示,可以在这里做判断,优化渲染效率。

componentWillUpdate(nextProps, nextState):组件即将更新。shouldComponentUpdate返回true或者调用forceUpdate之后,componentWillUpdate会被调用。不能在该钩子中setState,会触发重复循环。

componentDidUpdate():组件更新完成。除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。该钩子内setState有可能会触发重复渲染,需要自行判断,否则会进入死循环 。一般情况下:里面有定时器和异步请求时不会出现死循环。

componentWillUnmount():组件即将卸载。一般在componentDidMount里面注册的事件需要在这里删除。像在didmount里面设置的定时器可以在这里面进行清除。

参考文章    参考文章    新生命周期

 

动画

react-transition-group

//装包
npm install react-transition-group --save

基本用法

// 引包
import {CSSTransition} from 'react-transition-group';

// state
this.state = {
  show: true
}
{/* render() */}
<CSSTransition
  in={this.state.show}
  timeout={1000}
  classNames="fade"
  onEntered={el => {el.style.color = 'pink'}}
  unmountOnExit
  appear={true}>
  <h2>hello world</h2>
</CSSTransition>
<button onClick={this.handleToggle.bind(this)}>点我切换动画</button>
/* css */
.fade-enter, .fade-exit-done, .fade-appear{
  opacity: 0;
}
.fade-enter-active, .fade-appear-active{
  opacity: 1;
  transition: all 1s ease-in;
}
.fade-enter-done, .fade-exit{
  opacity: 1;
}
.fade-exit-active{
  opacity: 0;
  transition: all 1s ease-in;
}

效果图

分析一下CSSTransition标签中的属性:

in={this.state.show}:该动画根据this.state.show判断出入场。

timeout={1000}:过渡时间,必写。

classNames="fade":跟vue用法一样,css类名标识。

onEntered={el => {el.style.color = 'pink'}}:动画钩子函数。

unmountOnExit:跟vue中v-if指令效果一样,出场后销毁dom元素。

appear={true}:页面初始化时就启动进场动画,需要加入appear和appear-active样式。

列表动画

// 引包
import {CSSTransition, TransitionGroup} from 'react-transition-group';

// state
this.state = {
  list: []
}

// 添加列表函数
addList(){
  this.setState({
    list: [...this.state.list, '大家好']
  })
}
{/* render() */}
<TransitionGroup>        
  {
    this.state.list.map((item, index) => {
      return (
        <CSSTransition
          timeout={1000}
          classNames="fade"
          onEntered={el => {el.style.color = 'pink'}}
          unmountOnExit
          appear={true}
          key={index}>
          <div>{item}</div>
        </CSSTransition>
      )
    })
  }
</TransitionGroup>
<button onClick={this.addList.bind(this)}>点我添加列表</button> 

css样式跟上例基本用法一样。

效果图

分析一下,在列表动画中主要使用TransitionGroup标签和CSSTransition标签配合,这里CSSTransition标签中就不用in属性了,还有循环列表记得加key,而且这里是加在CSSTransition标签上,这里简单演示一下就用了index,实际应用中应避免使用index当key。

详情看官方文档

 

无状态组件

当一个组件中只有一个render函数,那么可以称之为无状态组件,一般常见为UI组件,像这种组件完全可以用一个函数代替,写一个函数传入props,然后返回一段jsx代码,效果完全一样。

function Comp(props) {
    return <h1>Hello, {props.name}</h1>;
}

 

路由

装包

npm install react-router-dom --save

基本使用

根组件应该包在Router标签内,这样等于全局所有组件都受路由管理。

import {
    HashRouter as Router
} from 'react-router-dom';

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

跟vue不一样的是react路由规则写在组件中,代码中Switch标签区域相当于vue中的router-view区域,但并不是说Switch与router-view相同。还有用不用Switch的区别NavLink与Link也有出入。组件中this.props.location.query获取query参数(query在Link标签中定义了),this.props.match.params获取params参数。

import {Switch, Route, Redirect, NavLink} from 'react-router-dom';

render(){
    return (
        <div>
            <div className="nav">
                {/* params参数 */}
                <NavLink to="/com_a/aaa">A组件</NavLink>
                {/* query参数 */}
                <NavLink to={{pathname: '/com_b', query: {lala: 321}}}>B组件</NavLink>
            </div>
            <Switch>
                <Route path="/com_a/:name" component={ComA} />
                <Route path="/com_b" component={ComB} />
                <Redirect to="/com_b" />
            </Switch>
        </div>
    )
}

Puppeteer是一个node爬虫很好用的工具。引用文章地址点击打开链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值