【React】组件

1. class组件

复杂的组件,需要记录自己内部状态的话,使用class组件,因为function不能有局部变量和方法,而class可以有。

 //一部分页面标签放在一个函数里
function App(){
  return (
    <div>
      app
    </div>
  )
}
//必须继承组件,添加extends React.Component
class App2 extends React.Component{

  constructor(props){ //声明变量必须写在constructor里面
    super(props)//使用constructor必须写这个
    this.state= {  变量必须写在this.state里
       number:0
    }
  }
 
      
  add(){
    this.setState({
      number: this.state.number += 1
    })
  }
  render(){ //局部render
    return (
      <div>
        app 2 {this.props.name}
        <div>
          {this.state.number} 
          <button onClick={this.add.bind(this)}>+</button>
        </div>
      </div>
    )
  }
}


render()

function render(){
  
  ReactDOM.render(
      <App2 name="qinglin" age="18"/>, 
      document.querySelector('#root'))
}

2. 函数组件

把组成一部分页面的标签写在一个函数中,叫做函数组件。

  • 在上一节中说过React的作者的第一个创举,组件当中体现了第二个创举:标签的名字就是函数,标签的属性的key value 理解成一个对象,函数的参数就是这个对象。
    例如:
let number = 0

add =()=>{
  number += 1
  render()
}

minus =()=>{
  number -= 1
  render()
}
 
 //一部分页面标签放在一个函数里
function App(){
  return (
    <div>
  //这里的Box1标签就是函数,代表页面一部分的标签,标签的属性其实是对象,下面两个函数的参数obj就是这个对象
      <Box1 name="加一" />
    </div>
  )
}

function Box1(obj){
  return (
    <div class="parent">
    我的名字是{obj.name}
    <hr />
      <span>{number}</span>
      <button onClick={add}>+</button>
      <button onClick={minus}>-</button>
    </div>
  )
}


render()

function render(){
  
  ReactDOM.render(
      //虚拟DOM,本质就是对象
      
      
      <App/>, //这是XML语法
      
      
      document.querySelector('#root'))
}





【涉及到的知识点】

  • this.setState ————

    • 优点:回对更新优化,会把多次更新结果只进行一次渲染就能完成
    • 缺点:同时带来了弊端,有时候会有多个执行语句时异步更新
  • DOM diff ——— react每次修改变量都会自动智能地去局部更新页面内,更新之前都会把最新信息跟之前相比较,然后只更新有变化的部分,这种非常友好的过程叫DOM diff。


3. 组件通信

3.1 父子通信
  • 子组件向父级组件传递信息:
    原理:父级组件传一个函数,子元素在必要时(回调)调用通信函数(通信函数被调用时还可以传给它一些参数页面中可以渲染出来)。
   //代码示例
这个App是父元素
class App extends React.Component{ 
    constructor(){
       this.state={
          ...
      }
      this.setState({
        ....
      })
    }

    通信函数1(){}
    通信函数2(){}
    //App父级组件会把两个通信函数分别传给子级组件div1 和 div2
    render(){
      return (
        <div>
          <div1 f1 = {this.通信函数1.bind(this)}></div1>
          <div1 f2 = {this.通信函数2.bind(this)}></div1>
        </div>
      )
    }
}

//两个div子组件会调用通信函数

//这个div1是子元素
class div1 extends React.Component{
    ....
    this.state.通信函数1()
}
//这个div2也是子元素
class div2 extends React.Component{
   ....
  this.state.通信函数2()
}
  • 父级组件向子级组件传递信息:
    父级组件通过 props 给子组件的某个属性传一个值
      function App(){
          return (
                <div>
                     <span message="你好!"/>
                </div>
          )
      }
      
    function span(props){
        return (
          <p>子级组件得到的信息是:{props.message}</p>
        )
     }
    
    ReactDOM.renfer(
       <App />,
       document.querySelector("root")   
    )
    

3.1 爷孙通信

原理:爷爷级组件把一个或多个函数传给父级组件,父级组件再把这个函数透传给子级组件,最后自己组建调用这个函数。

代码示例,
这个App是父元素
class App extends React.Component{ 
    constructor(){
       this.state={
          ...
      }
      this.setState({
        ....
      })
    }

    通信函数1(){}
    通信函数2(){}
    //App爷爷级组件会把两个通信函数分别传给父级组件parent
    render(){
      return (
        <div>
          <parent  
                  success1={this.success1.bind(this)}
                   success2={this.success2.bind(this)}
        />
        </div>
      )
    }
}

function parent(props){
  let 通信1 = props.通信函数1
  let 通信2 = props.通信函数2
  return (
    <div class="playground">
      //parent再把通信函数传给div孙子级组件
       <Track1 通信={通信1} />
       <Track2 通信={通信2}/>
    </div>
  )
}

div孙子级组件会调用通信函数

//这个div1是孙子组件
class div1 extends React.Component{
    ....
    this.state.通信()
}
//这个div2也是孙子元素
class div2 extends React.Component{
   ....
  this.state.通信2()
}
  • 类似父子关系组件之间的通信就是这样一次传给函数,最后子级调用这个函数的过程。

4 . 任意组件之间通信

  • 发布订阅模式(EventHub)
var eventHub = {
    //发布事件
    trigger(eventName,data){}, //参数一为事件名,参数二位要发布的数据
    //订阅事件
    on(eventName,function(){}) //参数一为事件名,参数二为调用函数
}


eventHub.on('事件名',function(){})//订阅,click是事件名称
eventHub.trigger('事件名',data)
  • 单向数据流:
    原理:一个组件向下延申拥有树形关系的子组件,那么如何在互相没有直接关系 的组件之间通信呢?对此React提供了一种发布订阅模式(eventHub)的功能,eventHub 的具体用法在上一内容中有。只要其中一个组件给页面发布修改请求,这个请求就会被最订阅机质收到,这个机质是个对象,只存在内存中,不会被渲染到页面中,订阅机制收到后给最高级的组件传递信息,然后由父向子级组件依次通过props传递调用函数最后被各个子组件调用,最后进行(DOM diff) 渲染。这样就可以在任意组件之间进行通信了。

  • Redux
    使用eventHub发布订阅模式的特点是所有的动作都是通过事件来完成,数据必须放在顶层组件。

    • 下面是一些约定名词:
      • store 所有存数据的地方
      • store 对象中的对于数据的操作叫 reducer
      • eventHub.on 订阅subscribe
      • eventHub.trigger 发布action
      • eventHub.trigger('eventName',data) eventName叫action type 、data 叫 payload
  • Redux的优点:
    1. eventHub的所有动作都是通过事件来进行的,而且事件名可以是任意的,所以可能会存在隐藏的Bug,对此Redux做出了调整:

      switch (action.type) {
          case 'event1':
            function() { }
            break;
          case 'event2':
          function() { }
            break;
            ....
        default:
          return {
        
        }
      }
    

就这样吧所有事件统一列在一个地方,防止重复使用

  1. Redux把所有数据写在顶层的组件中,并且只能只读取。
  2. 提高了前端的门槛,对于英语的要求较高。

5. Readux

  • 使用Redux的步骤:
    1. 声明一个store,专门保存数据的,
      声明时必须使用createStore,接受的参数叫counter的一个函数
        counter(state, action) {return 新的数据} //参数一为初始数据,参数二为### 1. class组件
      

复杂的组件,需要记录自己内部状态的话,使用class组件,因为function不能有局部变量和方法,而class可以有。

 //一部分页面标签放在一个函数里
function App(){
  return (
    <div>
      app
    </div>
  )
}
//必须继承组件,添加extends React.Component
class App2 extends React.Component{

  constructor(props){ //声明变量必须写在constructor里面
    super(props)//使用constructor必须写这个
    this.state= {  变量必须写在this.state里
       number:0
    }
  }
 
      
  add(){
    this.setState({
      number: this.state.number += 1
    })
  }
  render(){ //局部render
    return (
      <div>
        app 2 {this.props.name}
        <div>
          {this.state.number} 
          <button onClick={this.add.bind(this)}>+</button>
        </div>
      </div>
    )
  }
}


render()

function render(){
  
  ReactDOM.render(
      <App2 name="qinglin" age="18"/>, 
      document.querySelector('#root'))
}

2. 函数组件

把组成一部分页面的标签写在一个函数中,叫做函数组件。

  • 在上一节中说过React的作者的第一个创举,组件当中体现了第二个创举:标签的名字就是函数,标签的属性的key value 理解成一个对象,函数的参数就是这个对象。
    例如:
let number = 0

add =()=>{
  number += 1
  render()
}

minus =()=>{
  number -= 1
  render()
}
 
 //一部分页面标签放在一个函数里
function App(){
  return (
    <div>
  //这里的Box1标签就是函数,代表页面一部分的标签,标签的属性其实是对象,下面两个函数的参数obj就是这个对象
      <Box1 name="加一" />
    </div>
  )
}

function Box1(obj){
  return (
    <div class="parent">
    我的名字是{obj.name}
    <hr />
      <span>{number}</span>
      <button onClick={add}>+</button>
      <button onClick={minus}>-</button>
    </div>
  )
}


render()

function render(){
  
  ReactDOM.render(
      //虚拟DOM,本质就是对象
      
      
      <App/>, //这是XML语法
      
      
      document.querySelector('#root'))
}





【涉及到的知识点】

  • this.setState ————

    • 优点:回对更新优化,会把多次更新结果只进行一次渲染就能完成
    • 缺点:同时带来了弊端,有时候会有多个执行语句时异步更新
  • DOM diff ——— react每次修改变量都会自动智能地去局部更新页面内,更新之前都会把最新信息跟之前相比较,然后只更新有变化的部分,这种非常友好的过程叫DOM diff。


3. 组件通信

3.1 父子通信
  • 子组件向父级组件传递信息:
    原理:父级组件传一个函数,子元素在必要时(回调)调用通信函数(通信函数被调用时还可以传给它一些参数页面中可以渲染出来)。
   //代码示例
这个App是父元素
class App extends React.Component{ 
    constructor(){
       this.state={
          ...
      }
      this.setState({
        ....
      })
    }

    通信函数1(){}
    通信函数2(){}
    //App父级组件会把两个通信函数分别传给子级组件div1 和 div2
    render(){
      return (
        <div>
          <div1 f1 = {this.通信函数1.bind(this)}></div1>
          <div1 f2 = {this.通信函数2.bind(this)}></div1>
        </div>
      )
    }
}

//两个div子组件会调用通信函数

//这个div1是子元素
class div1 extends React.Component{
    ....
    this.state.通信函数1()
}
//这个div2也是子元素
class div2 extends React.Component{
   ....
  this.state.通信函数2()
}
  • 父级组件向子级组件传递信息:
    父级组件通过 props 给子组件的某个属性传一个值
      function App(){
          return (
                <div>
                     <span message="你好!"/>
                </div>
          )
      }
      
    function span(props){
        return (
          <p>子级组件得到的信息是:{props.message}</p>
        )
     }
    
    ReactDOM.renfer(
       <App />,
       document.querySelector("root")   
    )
    

3.1 爷孙通信

原理:爷爷级组件把一个或多个函数传给父级组件,父级组件再把这个函数透传给子级组件,最后自己组建调用这个函数。

代码示例,
这个App是父元素
class App extends React.Component{ 
    constructor(){
       this.state={
          ...
      }
      this.setState({
        ....
      })
    }

    通信函数1(){}
    通信函数2(){}
    //App爷爷级组件会把两个通信函数分别传给父级组件parent
    render(){
      return (
        <div>
          <parent  
                  success1={this.success1.bind(this)}
                   success2={this.success2.bind(this)}
        />
        </div>
      )
    }
}

function parent(props){
  let 通信1 = props.通信函数1
  let 通信2 = props.通信函数2
  return (
    <div class="playground">
      //parent再把通信函数传给div孙子级组件
       <Track1 通信={通信1} />
       <Track2 通信={通信2}/>
    </div>
  )
}

div孙子级组件会调用通信函数

//这个div1是孙子组件
class div1 extends React.Component{
    ....
    this.state.通信()
}
//这个div2也是孙子元素
class div2 extends React.Component{
   ....
  this.state.通信2()
}
  • 类似父子关系组件之间的通信就是这样一次传给函数,最后子级调用这个函数的过程。

4 . 任意组件之间通信

  • 发布订阅模式(EventHub)
var eventHub = {
    //发布事件
    trigger(eventName,data){}, //参数一为事件名,参数二位要发布的数据
    //订阅事件
    on(eventName,function(){}) //参数一为事件名,参数二为调用函数
}


eventHub.on('事件名',function(){})//订阅,click是事件名称
eventHub.trigger('事件名',data)
  • 单向数据流:
    原理:一个组件向下延申拥有树形关系的子组件,那么如何在互相没有直接关系 的组件之间通信呢?对此React提供了一种发布订阅模式(eventHub)的功能,eventHub 的具体用法在上一内容中有。只要其中一个组件给页面发布修改请求,这个请求就会被最订阅机质收到,这个机质是个对象,只存在内存中,不会被渲染到页面中,订阅机制收到后给最高级的组件传递信息,然后由父向子级组件依次通过props传递调用函数最后被各个子组件调用,最后进行(DOM diff) 渲染。这样就可以在任意组件之间进行通信了。

  • Redux
    使用eventHub发布订阅模式的特点是所有的动作都是通过事件来完成,数据必须放在顶层组件。

    • 下面是一些约定名词:
      • store 所有存数据的地方
      • store 对象中的对于数据的操作叫 reducer
      • eventHub.on 订阅subscribe
      • eventHub.trigger 发布action
      • eventHub.trigger('eventName',data) eventName叫action type 、data 叫 payload
  • Redux的优点:
    1. eventHub的所有动作都是通过事件来进行的,而且事件名可以是任意的,所以可能会存在隐藏的Bug,对此Redux做出了调整:

      switch (action.type) {
          case 'event1':
            function() { }
            break;
          case 'event2':
          function() { }
            break;
            ....
        default:
          return {
        
        }
      }
    

就这样吧所有事件统一列在一个地方,防止重复使用

  1. Redux把所有数据写在顶层的组件中,并且只能只读取。
  2. 提高了前端的门槛,对于英语的要求较高。

5. VanillaJs

  • 使用Redux之关键函数:
    声明一个store,专门保存数据的,
    声明时必须使用createStore,接受的参数叫counter的一个函数

        ```
         counter(state, action) {return 新的数据} //这个函数提前声明,函数的参数一为初始数据,      
        参数二为操作数据的函数
         var store = Redux.createStore(counter)   //接受一个函数为参数
       ```
    
  • 使用redux的思路:

    1. dispatch一个action
    2. counter函数生成一个新的state,然后触发一个事件
    3. 上一步出触发的事件被subscribe函数接受,
    4. subscribe函数会调用render函数,然后重新render
    5. 第二次render之后在得到新的store,浏览器DOM diff 之后渲染页面

6. Redux

  • react比vanilla好的地方是会DOM diff,局部更新。

7. React-Redux

7.1 API
  • connect(mapStateToProps,mapDispatchToProps)(App)
    一个括号为一个参数,第一个括号里可有多个参数,第二个括号为第二个参数 ;功能是把数据、数据变更动作、组件组合起来。
  • Provider() 从React-Redux引入之后以标签的形式写成包围组件,功能是获取state,然后通知到里面的每一个组件

  • 写这一节博客,做了简单的项目[https://github.com/cnqinglin/react-redux-v1]之后的最大的感觉就是React社区的东西其实不难,但为什么总感觉很难是因为它给就概念都给了一个新的名字。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 作为一个合格的开发者,不要只满足于编写了可以运行的代码。而要了解代码背后的工作原理;不要只满足于自己的程序...
    六个周阅读 12,710评论 1 33
  • 今天来看一下react组件之间是怎么进行通讯的。react推崇的是单向数据流,自上而下进行数据的传递,但是由下而上...
    亲亲qin阅读 11,201评论 2 12
  • 很感谢https://segmentfault.com/u/cwl提供的答案React 组件间通讯 说 React...
    喵呜Yuri阅读 4,417评论 0 2
  • react是以组合组件的形式组织的,那么组件间是如何传递信息的呢? 父组件向子组件通信 parent组件传给chi...
    DCbryant阅读 3,365评论 0 0
  • 刚刚接触到这个东西,也不是很熟悉。我也就走马观花式的观察。怀着好奇的心态,经过我的多次看财经新闻的经历,我终于对财...
    day向上阅读 1,639评论 0 0

友情链接更多精彩内容