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()}>点击切换

      );
      }

      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)
  }//箭头函数
}
相关推荐
林希_Rachel_傻希希6 小时前
web性能优化之————图片效果
前端·javascript·面试
Darling噜啦啦6 小时前
前端存储与 this 指向完全指南:从 LocalStorage 实战到 call/apply/bind 深度解析
前端·javascript
wei1986216 小时前
.net添加web引用和添加服务引用有什么区别?
java·前端·.net
非科班Java出身GISer7 小时前
ArcGIS JS API 5.0 ESM 双模块系统冲突解决方案
arcgis·arcgis js 引入问题·arcgis js amd·arcgis esm引入问题·arcgis js 资源冲突
格子软件8 小时前
2026年GEO优化系统源码级状态机与多模型调度拆解
java·前端·vue.js·人工智能·vue·geo
HUMHSX8 小时前
Vue 项目启动全流程解析:从入口文件到全局指令注册与页面渲染
前端·javascript·vue.js
有颜有货9 小时前
PMC生产排产的4种算法,一次讲清
java·服务器·前端
小虎牙0079 小时前
Android kotlin图片库Coil源码详解
android·前端
随风一样自由9 小时前
【前端领域】前端开发核心应用场景与落地实践
前端·前端框架
an317429 小时前
弹窗数据流设计的两种高阶架构实践
前端·vue.js·架构