12.23_React_02

表单↓

❤ 受控组件

判断是否受控组件:看表单内的值是否受到state的控制

作用:将表单的可变状态数据和state都保存在state中 方便进行管理

为什么要做成受控组件:因为在提交订单时 需要收集用户的数据 并提交 受控组件能很方便的收集用户数据 非受控组件代码较为冗余

设置步骤:

  1. 给input添加value属性并和state中对应的数据进行绑定 value= {this.state.数据名称} 让其表单输入框的数据和state相连接
  2. 给input设置onChange事件 onChange = {e => this.事件名称({ txt: e.target.value})} 在事件处理函数中 e.target.value拿到输入的值 作用是让表单后续更新改动也可以监听到数值的变化 达到响应更新
  3. state只能公共setState来修改 通过this.setState将获取到的最新数值赋值给state 达到检测数据变化后更新数据的操作
// 文本框
Class Hello extends React.Component {
    state = {
        txt: ''
    }
    // 事件处理程序
    handleTxt = (e) => {
        this.setState() {
            txt: e.target.value
        }
    }
    render() {
        return (
            <input type="text" value={this.state.txt} onChange={this.handleTxt()}}</input>></input>
        )
    }
}

// 优化  使用一个事件处理程序来处理多个表单
Class Hello extends React.Component {
    state = {
        txt: '',
        content: '',
        city: 'xx1',
        isChecked: false
    }
    // 事件处理程序
    handleTxt = (e) => {
        this.setState() {
            txt: e.target.value
        }
    }
    // 优化后的事件处理程序
    handleForm = (e) => {
        // 首先获取dom对象
        const target = e.target
        // checkbox是特殊value类型 所以需要判断类型来获取
        // 为了保证能拿到所有类型的value
        const value = target.type === 'checkbox'
        ? target.checked
        : target.value
        
        // 获取设置的name
        const name = target.name
        // 通过settState修改state
        this.setState({
            // 此处的name相当于一个变量
            [name]:value
        })
    }
    render() {
        return (
            <div>
                <!-- 文本框 -->
            	<input type="text" 
                    value={this.state.txt} 
                    onChange={this.handleTxt()}}>						</input>
                <br/>
                
                <!-- 富文本框 -->
                <textarea name="content" 
                    value={this.state.content} 
                    onChange={this.handleForm}>							</textarea>
        		<br/>
                <!-- 下拉框 -->
                <select name="city" 
                    value={this.state.city} 
                    onChange={this.handleForm}>
          			<option value="sh">xx1</option>
          			<option value="bj">xx2</option>
          			<option value="gz">xx3</option>
        		</select>
        		<br/>
                <!-- 复选框 -->
                <input type="checkbox" 
                    name="isChecked" 
                    checked={this.state.isChecked} 
                    onChange={this.handleForm} />
            </div>
            
        )
    }
}
// 渲染类组件
ReactDOM.render(<App />,document.getElementById('root'))

// name做了什么:做了区分 未来更新对应的状态
// 为什么name能做到更新未来对应的状态
// 因为每个表单都使用了一个名为name的外包装 包装内存入着各种名称和state一一对应  当触发每个不同的表单会触发里面对应不同的value 所以当触发的是txt文本表单 此时的name就是txt中的value

非受控组件 Ref

通过ref拿到dom对象来获取数据改变数据

// 类组件中
constructor() {
	super()
	// constructor中创建ref
	this.ref = React.createRef()
}
// 事件处理程序
getText = (e) => {
    // 将拿到的数值打印到控制台中
    console.log(this.txtRef.current.value)
}

render() {
    return (
    	<div>
            <!-- 通过绑定ref拿到value -->
        	<input type='text' ref={this.ref}></input>
            <button onClick={this.getText()}></button>
        </div>
    )
}

❤ props 组件之间通信

组件是封闭的一个单独的个体 数据都是私有的 但是在组合组件实现一些功能时 不可避免的需要让组件之间进行数据的传递 这种时候就要使用到组件通信

作用:接受传递给组件的数据

特点:

  1. 可以传递任意数据类型 数组、属性、函数、标签 非字符串的需要{}包裹
  2. 是个只读属性 不能修改数值 能使用setState修改嘛?
  3. 在类组件的constructor中不能直接通过this.props接收 需要通过constructor形参来接收 因为实例对象在生成时就会调用 此时的props未定义
// 类组件
class Hello extends React.Component {
    constructor(props) {
        super(props)
        // 这样才能再constructor中拿到props
        console.log(this.props)
    }
}

如何传递数据: 通过给要传递数据的组件标签 添加属性

ReactDOM.render(<hello name="jack" age={18} />,document.getElementById('root'))
// 传递非字符串的数据 都用{}包裹 规则和表达式差不多

如何接收数据: 函数组件通过形参props接收数据 类组件通过this.props接收

// 函数形式
// 函数通过形参接收
Hello = (props) => {
    console.log(props)
    // { name:'jack', age:18}
    return (
    	<div>接收到的数据: {props.name,props.age}</div>
    )
}

// 类组件形式
class Hello extends React.Component {
    render() {
        // 类组件接收使用this.props
        return (
        	<div>接收到的数据:{this.props.age}</div>
        )
    }
}

* 父子传值

父子传递的不限于组件的类型 只要是组件包含组件都能传递

// 父类组件
class Father extends React.component {
    // 父组件的私有数据 要被传递的数据
    state = {
        userName:'一点点'
    }
	render() {
        return (
        	<div>
                <!-- 通过给子组件的的标签绑定父组件state私有数据 -->
            	子组件标签: <Child name= {this.state.userName} />
            </div>
        )
    }
}

// 子函数组件 子组件就能通过props接收到数据了
const Child = (props) => {
    return <div>子组件接收到的数据: {props.name} </div>
}

* 子传父

父组件向包裹的子组件标签传递一个回调函数

子组件在组件内部触发这个回调函数 将需要被传递的自身私有数据通过回调函数的形参传递给父组件

总结:哪个父组件需要子组件的数据 就提供一个回调函数接收

// 父组件
class Father extends React.conponent {
    // 父组件的私有数据
    state = {
        fatherMsg:''
    }
	// 父组件定义的回调函数 由子组件触发 父组件不触发
	getChildMsg = data => {
        console.log('子组件传递过来的参数',data)
        // 将子组件传递来的数据存入到父组件私有数据中使用
        this.setState({
            fatherMsg: data
        })
    }
	render() {
        return (
        	<div>
                子组件传递来的数据:<span>{this.state.father}</span>
            	子组件标签: <Child getFather(this.getChildMsg()) />
            </div>
        )
    }
}

// 子组件
class Child extends React.component {
	// 子组件的私有数据 即将传递给父组件的数组
	state = {
        msg:'我是子组件的数据'
    }
	// 子组件的事件处理程序
	childMsg = () => {
        // 子组件通过this.props拿到父组件传递过来的和回调函数
        this.props.getFather(this.state.msg)
    }
	render() {
        return {
            <!-- 子组件再点击时触发调用传递参数函数 -->
            <button οnclick={this.childMsg()}></button>
        }
    }
}

* 兄弟传值

什么是兄弟传值:两个组件中的相互传值 需要通过最近的父组件这个中转站

状态提升:将两个子组件中的状态存储到父组件中 称为状态提升

原理:是子传父 和父传子的结合 因为私有状态数据提升到了父组件的私有状态中 所以当子组件传递给父组件数据 并父组件修改了传递过来的数据 另一个链接这个私有数据的子组件会自然而然发生改变

// 父组件
class Father extends React.Component {
    // 父组件的私有数组 提供共享
	state = {
        count: 0
    }
    // 父组件提供的修改数据方法
    onFatherCount = () => {
        this.setState({
            count: this.state.count + 1
        })
    }
    
    render() {
		return (
            // 此处是子组件2是主动那一方 子组件1是被动的一方
        	<div>
            	<Child1 count={this.state.count} />
                <Child2 onIncrement={this.onFatherCount} />
            </div>
        )
	}
}

// 函数子组件1 
const Child1 = props => {
    // 子组件1通过props拿到父组件的私有数据
    return (
    	<div>
        	<h1>计数器 {props.count}</h1>
        </div>
    )
}

// 函数子组件2
const Child2 = props => {
    return (
        // <!-- 子组件2事件处理程序 -->
    	<div>
        	<button onClick={() => props.onIncrement()}>+1按钮</button>
        </div>
    )
}

// 渲染组件 因为子组件嵌套在父组件中 所以此时只需要渲染父组件
ReactDOM.render(<Father />, document.getElementById('root'))

* Context 祖传

作用:在层级过多时 需要跨组件传递私有数据

实际运用场景:主题的颜色 一般各个组件都需要 层级比较复杂时 就可以使用context

// 创建这个Context 解构出得到两个需要的属性 
// Provider:提供数据 包裹根组件
// Consumer:消费数据 包裹接受数据的结构
const {Provider, Consumer} = React.createContext()
// 父组件
class App extends React.Component {
    // 传递多个数据时要怎么弄? 
    state = {
        yanse: 'pink'
    }
    render() {
        return (
            // 要传递的值 写在Provider标签的value属性中
        	<Provider value="pink">
            	<div>
                	<Node />
                </div>
            </Provider>
        )
    }
}

// 嵌套关系 APP->Node->SubNode->Child

// 子组件 Node
const Node = props => {
    return (
    	<div>
            Node组件
        	<SubNode />
        </div>
    )
}

// 子组件 SubNode
const SubNode = props => {
    return (
    	<div>
            SubNode 组件
        	<Child />
        </div>
    )
}

// 子组件 Child
const Child = props => {
    // 子组件作为子子子组件 但是拿到了父组件的value值 达成跨组件传值
    return (
    	<div>
        	<Consumer>{data => <span>我是Child节点:{data} </span>}</Consumer>
        </div>
    )
}

// 渲染父组件
ReactDOM.render(<App />, document.getElementById('root'))

children属性

当组件标签变成双标签 包裹了其他节点会自动生成子节点 children属性

作用:可以通过{props.children} 属性能拿到所有子节点 并将其利用差值表达式将这个组件标签的子节点全部渲染到页面上

class App extends React.Component {
    render() {
        return (
        	<div>App组件</div>
            {this.props.children}
        )
    }
}

// 渲染App组件
// 组件标签在基础学到过 标签中可以让任何类型的元素 标签 函数...
ReactDOM.render(<App><span>App的子节点<span>子节点的子节点</span></span></App>, document.getElementById('root'))

props校验

作用:是第三方插件 校验props外来传入数据的格式数据类型等 在传入的数据对象不符合要求时给出明确的错误 让组件在使用更加明确

  1. 安装

    • npm i props-types
  2. 导入

    • import PropTypes from 'prop-types'
  3. 使用

    • 组件名.propTypes={}
  4. 校验规则通过PropType对象来指定

    // 导入PropType
    import PropType from 'prop-types'
    
    // 函数组件
    const App = (props) => {
        return (
            <div>
            	<h1> {props.colors} </h1>
                <h2> {props.name} </h2>
                <h3> {props.user}</h3>
            </div>
        )
    }
    // 常见类型
    App.PropTypes ={
        // 设置colors属性为array类型 假如传入的不是数组类型 会给出报错
        colors: PropTypes.array
    }
    
    // 必选 isRequired
    App.PropTypes={
    	name:propTypes.string.isRequired
    }
    
    // 特定对象 shape
    App.PropTypes={
    	user:propTypes.shape({
            color: PropTypes.string,
            fontSize: PropTypes.number
        })
    }
    
    // 常见类型: array、bool、func、number、object、string
    // React元素类型: element
    // 必选: isRequired
    // 特定对象: shape({})
    

更多查看官方手册约束规则

defaultProps 默认值

作用:在没有传入props数值时生效的数据 为了不影响代码的基本运行

使用场景:分页组件 当分页组件默认展示多少条条数时 就是使用的默认值

// 创建函数组件
const App = (props) => {
	return (
		<div>
		默认值: {props.pageSize}
		</div>
	)
}

// 设置默认值
App.defaultProps = {
	pageSize: 10
}
// 当传入pageSize属性值时 会覆盖默认值 以传入的数值为准
ReactDOM.render(<App pageSize ={20}/>, document.getElementById('root'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值