React---day8

9.6 不可变数据的力量

我们知道是不能够修改this.state里面的数据的

举个例子

复制代码
export class App extends React.PureComponent{
    constructor(){
        super();
        this.state = {
            userList:[
                {name : "tom" , age : 18},
                {name : "lily" , age : 20},
                {name : "tiki" , age : 18},
            ]

        }
    }
    render(){
        const userList =this.state.userList
        return (
           <div>
             <ul>
               {
                userList.map((item , index , arr) => {
                    return (
                        <li key={index}>{item.name} + {item.age}</li>
                    )

                })
               }
            </ul>
            <button onClick={() => this.addNewUser()}>点击添加</button>
           </div>
        )
    }

不推荐的做法:

复制代码
        const newData = {name : "hcy" , age : 19}
        this.state.userList.push(newData);
        this.setState({
            userList:this.state.userList
        })

因为我们修改了state里面的数据,但是这种方式直接修改原数组,不符合 React 的不可变性原则

我们的APP继承了PureComponent,它有shouldcomponnets方法,这个方法必须发生改变才会执行,但是我们这样的方法指向同一个地址(相同)所以是不会改变的

**推荐做法:**不要直接修改 state,应该用新数组。

复制代码
    const newData = {name : "hcy" , age : 19}
        this.setState({
            userList:[...this.state.userList , newData]//不要直接修改 state,应该用新数组。
        })

9.7 全局事件传递events

开发中跨组件之间的事件传递,使用events

通过npm或者yarn来安装events

复制代码
 npm add events

events常用的API:

  • 创建EventEmitter对象:eventBus对象;
  • 发出事件:eventBus.emit("事件名称", 参数列表);
  • 监听事件:eventBus.addListener("事件名称", 监听函数);
  • 移除事件:eventBus.removeListener("事件名称", 监听函数);

事件演练:

复制代码
import React, { PureComponent } from 'react'
import {EventEmitter} from 'events'
// 需求:点击profile中的按钮->进行跨组件之间的事件传递
// 1、创建EventEmitter对象:eventBus对象
const evebtBus = new EventEmitter();

export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Header />
        <Profile/>
      </div>
    )
  }
}
class Header extends PureComponent{
    // 进行监听
    componentDidMount(){
        // 添加事件监听
        // 3、监听事件:eventBus.addListener("事件名称", 监听函数);
        // (eventName: string | symbol, listener: (...args: any[]) => void):
        // this.handleSayHelloListener:没有括号,因为是函数
        evebtBus.addListener("sayHello" , this.handleSayHelloListener)
    }
    componentWillUnmount(){
        // 取消事件监听
        //  (...args: any[]) => void)
        // 4、 移除事件:eventBus.removeListener("事件名称", 监听函数);
        evebtBus.removeListener("sayHello" ,this.handleSayHelloListener)
    }
    // ...args
    // 多个参数要写多个形参
    handleSayHelloListener(str , num){
        console.log(str + num);
    }
    render (){
       return (
         <div>
            Hello World
        </div>
       )
    }
}
class Profile extends PureComponent{
    render (){
      return(
          <div>
            Hello Profile
            <button onClick={() => this.emmitEvent()}>点击Profile</button>
        </div>
      )
    }
// 2、发出事件:eventBus.emit("事件名称", 参数列表);
    emmitEvent(){
        evebtBus.emit("sayHello" , "Hello Home" , 123)
    }
}

10、受控和非受控组件

10.1 refs的使用

  • 方式一:传入一个对象
    • 对象是通过 React.createRef() 方式创建出来的;
    • 使用时获取到创建的对象其中有一个current属性就是对应的元素;
  • 方式二:传入一个函数
    • 该函数会在DOM被挂载时进行回调,这个函数会传入一个 元素对象,我们可以自己保存;

    • 使用时,直接拿到之前保存的元素对象即可;

      import React, { PureComponent } from 'react';
      import Pure from './Pure';
      export default class App extends PureComponent {
      constructor() {
      super();
      this.titleRef = React.createRef();
      this.titleEle = null;
      }

      render() {
      return (


      {/* 1、React.createRef() /}

      Hello World


      {/
      2、传入一个函数 */}
      <h2 ref={(args) => this.titleEle = args}>Hello World
      <button onClick={() => this.changeRef()}>点击切换</button>

      );
      }

      changeRef() {
      this.titleRef.current.innerHTML = "Hello React";
      this.titleEle.innerHTML = "Hello React"
      }
      appAdd(){
      console.log(this.pureRef.current.btnAdd());
      }
      }

10.2 ref的类型

ref 的值根据节点的类型而有所不同:

  • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性;
  • 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性;
  • 你不能在函数组件上使用 ref 属性,因为他们没有实例;

举一个组件上使用ref的例子:

复制代码
          // 组件的ref
    this.pureRef = React.createRef();
      {/* 3、当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性; */}
        <Pure  ref={this.pureRef}/>
        <button onClick={() => this.appAdd()}>app+1</button>

10.3 受控组件

受控组件是单元素(如<input><textarea>等)的值由React的state进行"控制",即组件的状态(state)是唯一数据源

复制代码
import React, { PureComponent } from 'react'

export default class App extends PureComponent {
    constructor(){
        super();
        this.state = {
            username:""
        }
    }
  render() {
    return (
      <div>
        <form>
            <input 
            type='text'
            value={this.state.username}
            onChange={(e) => this.handleChange(e)}
            />
             <input 
            type='submit'
            onClick={(e) => this.handleSubmit(e)}
            />
        </form>
      </div>
    )
    
  }
  handleSubmit(event){
    event.preventDefault();
    console.log("提交内容:",this.state.username)
  }
  handleChange(event){
   this.setState({
    username:event.target.value
   })

  }
}

<input>value 属性绑定了 this.state.username,输入框的内容只能通过 setState 来改变。每当用户输入内容时,onChange 事件会触发 handleChange,进而更新 state,React 再把最新的 state 赋值给 input 的 value。

总结:

受控组件的输入值受 React 组件的 state 控制,React 负责管理和同步表单数据,这就是"受控"的含义。

其他受控通过组件:比如select

复制代码
import React, { PureComponent } from 'react'

export default class App extends PureComponent {
    constructor(){
        super();
        this.state = {
            fruit:"apple"//默认为苹果
        }
    }
  render() {
    return (
      <div>
        <form onSubmit={(e) => this.handleSubmit(e)}>
            {/* 选择器 */}
            <select 
            value={this.state.fruit}
            name='fruits'
            onChange={(e) => this.handleChange(e)}>
                <option value="apple">苹果</option>
                <option value="oringe">橘子</option>
                <option value="bannana">香蕉</option>
            </select>
        </form>
      </div>
    )
    
  }
  handleSubmit(event){
    event.preventDefault();
    console.log("提交内容:",this.state.fruit)
  }
  handleChange(event){
   this.setState({
    fruit:event.target.value
   })

  }
}

受控组件---多输入

要是不抽取代码就会很冗余

复制代码
import React, { PureComponent } from 'react'

export default class App extends PureComponent {
    constructor(){
        super();
        this.state = {
            username:"",
            password:""
        }
    }
  render() {
    return (
      <div>
        <form>
            <input 
            type='text'
            name='username'
            value={this.state.username}
            onChange={(e) => this.handleChange(e)}
            />
             <input 
             name='password'
            type='password'
            value={this.state.password}
            onChange={(e) => this.handleChange(e)}
            />
             <input 
            type='submit'
            onClick={(e) => this.handleSubmit(e)}
            />
        </form>
      </div>
    )
    
  }
  handleSubmit(event){
    event.preventDefault();
    const {username , password } = this.state;
    console.log("提交内容:",username , password )
  }
//   handleusernameChange(event){
//    this.setState({
//     username:event.target.value
//    })

//   }
//    handlepasswordChange(event){
//    this.setState({
//     password:event.target.value
//    })

//   }
  handleChange(event){
    this.setState({
        [event.target.name] : event.target.value
    })

  }
//   我们可以把handleChange写为一个,因为她们的样式是都是:
//     handle{key}Change(event){
//    this.setState({
//     {key}:event.target.value
//    })

//   }
// 我们只需要动态更新key就好
// 1、input设置name
// 2、event.target.name得到不同的key
}

10.4 非受控组件的使用

如果要使用非受控组件中的数据,那么我们需要使用 ref 来从DOM节点中获取表单数据。

在非受控组件中通常使用defaultValue来设置默认值;

复制代码
import React, { createRef, PureComponent } from 'react'

export default class App extends PureComponent {
    constructor(){
        super();
        this.nameRef = createRef()//创建ref对象
    }
  render() {
    return (
      <div>
        <form>
            <input 
            type='text'
            ref={this.nameRef}//绑定ref
            />
             <input 
            type='submit'
            onClick={ this.handleSubmit}
            />
        </form>
      </div>
    )
    
  }
  handleSubmit = (event) => {
    event.preventDefault();
    console.log("提交内容:",this.nameRef.current.value)
  }//箭头函数
}
相关推荐
_r0bin_2 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
IT瘾君2 小时前
JavaWeb:前端工程化-Vue
前端·javascript·vue.js
potender2 小时前
前端框架Vue
前端·vue.js·前端框架
站在风口的猪11083 小时前
《前端面试题:CSS预处理器(Sass、Less等)》
前端·css·html·less·css3·sass·html5
程序员的世界你不懂3 小时前
(9)-Fiddler抓包-Fiddler如何设置捕获Https会话
前端·https·fiddler
MoFe13 小时前
【.net core】天地图坐标转换为高德地图坐标(WGS84 坐标转 GCJ02 坐标)
java·前端·.netcore
去旅行、在路上4 小时前
chrome使用手机调试触屏web
前端·chrome
Aphasia3114 小时前
模式验证库——zod
前端·react.js
lexiangqicheng5 小时前
es6+和css3新增的特性有哪些
前端·es6·css3
拉不动的猪6 小时前
都25年啦,还有谁分不清双向绑定原理,响应式原理、v-model实现原理
前端·javascript·vue.js