react基础知识梳理

63 阅读6分钟

谈谈JSX

  1. 引入原因:虽然浏览器只能识别JS语法,但是操作原生的JS语法非常繁琐,效率低下,故此有了JSX,目的就是方便书写,提高效率,所以需要依赖一个babel(将JSX语法转换为JS语法),script标签type类型为text/babel

  2. 本质:React.createElement(component,props,...children)的语法糖,标签名可以任意,一般大写的表示组件标签

  3. 作用:简化创建虚拟DOM

    3.1写法:

var ele=<h1>hello jsx! </h1>

注意1:他不是字符串,也不是HTML/XML标签

注意2:他最终产生的就是一个JS对象

4.规则

1.定义虚拟dom时,不要写引号

2.标签中混入JS表达式时要用{}

3.样式的类名不要用class,而是使用className代替

4.内联样式,使用style={{key:value}}形式

5.只有一个根标签,且标签闭合

6.标签首字母,小写时表示转为html同名标签,大写时为对应的组件标签

组件分类

函数式组件:一个函数就是一个组件,return一份DOM结构

特点:

1.没有生命周期,也会被更新并挂载,但是没有生命周期函数

2.没有this(组件实例)

3.没有内部状态(state)

4.16.8版本以后有hooks弥补一些缺陷

优点:轻量,如果组件没有涉及内部状态,只是用来渲染数据,那么就用函数式组件,性能较好

基本结构:

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

类组件:分为普通类组件(React.Component)以及纯类组件(React.PureComponent)

区别

 背景:先了解下React生命周期函数shouldComponentUpdate,这个函数返回一个布尔值,
 如果返回true,那么当pros或者state改变时候进行更新;返回false,当props或state改变时候不更新,默认返回true。
 这里的更新不更新,其实说的是执不执行render函数,如果不执行render函数,那么该组件和其子组件都不会重新渲染
 不同点:
 1.继承PureComponent时,不能再重写shouldComponentUpdate
 2.React.PureComponent基于shouldComponentUpdate做了一些优化,通过props和state的浅比较来实现shouldComponentUpdate,
 也就是说,如果是引用类型的数据,只会比较是不是同一个地址,而不会比较具体的地址存的数据是否完全一致

基本结构:

class ListOfWords extends React.PureComponent {
    render() { return <div>PureComponent渲染结果:{this.props.words.join(',')}</div>; } } 
class WordAdder extends React.Component { 
   constructor(props) { 
      super(props); 
      this.state = { words: ['marklar'] }; 
      this.handleClick = this.handleClick.bind(this); }
   handleClick() { 
   // This section is bad style and causes a bug const words = this.state.words;    
   words.push('marklar'); 
   this.setState({words: words}); } 
   render() { 
   // slice() 方法返回一个新的数组对象
   return ( 
       <div> <button onClick={this.handleClick}>click</button> 
       <div>Component渲染结果:{this.state.words.join(',')}</div>
       <ListOfWords words={this.state.words} /> 
       <ListOfWords words={this.state.words.slice(0)} /> </div>
       ); 
       } }
       ReactDOM.render( <WordAdder />, document.getElementById('root') )

组件实例对象三大属性

state

 state是组件实例对象最重要的属性,必须是对象的形式

 组件被称为状态机,通过更改state的值来达到更新页面
 
 组件render中的this指向组件实例对象
 
 状态数据的改变不能直接赋值,需要用setState()方法
 
 组件中this为undefined,怎么解决(关键点是将this指向为当前的实例对象)
 
    将自定义的函数改为表达式+箭头函数的形式(推荐)
    handleClick = () => { console.log(this.state.count) }
    
    在构造器中用bind()强制绑定this
    this.handleClick = this.handleClick.bind(this)
    
    函数科里化,即函数中返回一个箭头函数
    handleClick() { 
    // 这里的 this 指向是什么?那就看是谁调用的!
    return () => { console.log(this.state.count)        
    } }
    
    在标签体中使用箭头函数调用,或者使用bing绑定this
    <button onClick={() => this.handleClick()}>+1</button>  
    <button onClick={this.handleClick.bind(this)}>+1</button>

props

 简介,类的继承子类,必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,
 必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。
 如果不调用super方法,子类就得不到this对象
 
 props可以传递任何数据类型,并且props是只读的(单向数据流),所有的React组件必须像纯函数那样使用它们的props
 
 props的传递:通过标签属性从组件外向组件内传递数据
 
 ReactDOM.render(<Person name="Jack" age="19" sex="man" />,  document.getElementById('test1'))//单个传递  
 const p = { name: '老王', age: 30, sex: 'man' }
 ReactDOM.render(<Person {...p}/>, document.getElementById('test2'))//批量传递
 
 props的验证:使用propType属性并配合prop-types三方库实现prop验证(不需要另外下载,已集成在脚手架中)
 给类自身添加静态属性(staticstatic propTypes={name:PropTypes.string,age:PropTypes.number}

refs

   认识:refs存放是的所有使用了ref标识的对象,refs常用于管理焦点、文本选择、媒体播放、强制动画、表单校验等
   
   字符串形式的ref
   
   定义:直接在标签上写ref=‘xxx’
   使用:this.refs.xxx
   注意:官方不推荐此方式,推荐使用回调函数或者createRef()代替
   
   回调函数形式的ref
   
   定义:自己定义,但是自己不调用,别人帮你调用
   使用:利用箭头函数没有this特性,把当前的ref所在的节点当作函数的实参传递给你所定义的那个属性
   class Demo extends React.Component { 
   render() { 
    // 箭头函数没有this,往外找是Demo的实例对象, 把当前的ref所在的节点当作函数的实参传给了input1属性 
    return ( 
       <div> 
       <input ref={currentNode => this.input1 = currentNode} type="text" placeholder="点击按钮提示数据"/>&nbsp; 
       <button onClick={this.showData}>点击提示左侧的数据</button>&nbsp; 
       </div> ) } 
       showData = () => { const {input1} = this; console.log(this); console.log(input1.value); } } 
       ReactDOM.render(<Demo />, document.getElementById('test'));
       
   createRef创建ref
   
   定义:React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,不同的节点不能使用同一个,是覆盖操作,会替换之前的ref
   使用
   class Demo extends React.Component { 
   // React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,不同节点不能使用同一个,是覆盖操作,会替换掉之前的那个ref myRef = React.createRef(); myRef2 = React.createRef(); 
   render() { 
      return ( 
         <div> 
         <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>&nbsp;
         <button onClick={this.showData}>点击提示左侧的数据</button>&nbsp; 
         <input ref={this.myRef2} onBlur={this.blurData} type="text" placeholder="失去提示数据"/>&nbsp; 
         </div> ) } 
         showData = () => { 
         console.log(this); console.log(this.myRef); 
         // {current: input} ---- current不能改,React规定是这样 console.log('myRef ==> ', 
         this.myRef.current.value) } 
         blurData = () => { console.log('myRef2 ==> ',this.myRef2.current.value) } } 
         ReactDOM.render(<Demo />, document.getElementById('test'));

react路由

 初识:依赖react-router-dom,专门用来实现一个SPA单页应用,
 常用内置组件<BrowserRouter><HashRouter><Route><Redirecrect><Link><NavLink><Switch>
 
 一般组件与路由组件的不同之处
 写法不同   一般组件 <Demo />  路由组件 <Route path="/demo" component={Demo}/>
 接收的props不同  一般组件 标签传递什么,就能接收什么  路由组件  接收三个固定的属性 history、location、match
 
 路由组件传递参数
   params参数
      路由链接(携带参数):<Link to="/demo/tom/18">xx</Link>;
      注册路由(声明参数):<Route path="/demo/:name/:age" component={demo}/>;
      接收参数:this.props.match.params
   search参数
      路由链接(携带参数):<Link to="/demo?name=tom&age=18">xx</Link>
      注册路由(无需声明,正常注册即可):<Route path="/demo" component={demo}/>
      接收参数:this.props.location.search
      备注:获取到的search是urlencoded编码字符串,需借助querystring解析
   state参数
      路由链接(携带参数):<Link to={{path:‘/demo’,state:{name:"tom",age:"18">xx</Link>
      注册路由(无需声明,正常注册即可):<Route path="/demo" component={demo}/>
      接收参数:this.props.location.state
      备注:刷新可能会丢失参数 (BrowserRouter模式下不会丢失,HashRouter模式下会丢失)