react-组件之间的数据共享

React 学习之路02

    • 1.表单处理
    • 2.组件通讯介绍
    • 3. props 深入了解

1.表单处理

受控组件的概念:

  1. HTML 中表单元素时可输入的,也就是有自己的可变状态
  2. React 中可变状态通常保存在 state 中,并且只能通过 setState() 方法来修改
  3. React 希望将 state 与 表单元素 value 绑定到一起,由 state 的值来控制表单元素的值的
  4. 受控组件: 值受到 React 控制的表单元素

受控组件使用步骤

  1. 控制表单元素值的来源:在 state 中添加一个状态,作为表单元素的 value 值
  2. 控制表单元素值的变化:给表单元素绑定 change 事件,将表单元素中输入的值同步到 state
  3. 受控组件使用示例 文本框 、富文本、下拉框、复选框
import React from 'react'
/**
 *  1. input 元素
 *  2. textarea 元素
 *  3. select 元素
 *  4. checkbox 元素
 */

export default class App extends React.Component {
  state = {
    value: '',
    content: '',
    selectValue: '',
    checkbox: false
  }

  change = (e) => {
    // 2. 根据表单元素类型获取对应值
    // 2.1 获取表单元素
    const target = e.target
    // 2.2 target.type --- 表单元素类型
    // 由于复选框控制的值变化 和 其他 input 框不一样,所以这里先判断他的类型 然后 从而拿到对应的值
    const value = target.type === 'checkbox' ? target.checked : target.value

    // 3. 通过 [name] 来修改对应的state
    // 3.1 target.name -- 获取元素的名称
    const name = target.name
    // 3.1 根据获取的 name 值修改 state
    this.setState({
      [name]: value
    })
  }

  render () {
    return (
      <div>
        {/* 1. 给表单元素添加name属性,名称与 state 相同 */}
        <input name="value" type="text" value={ this.state.value } onChange={ this.change } />
        <textarea name="content" value={this.state.content} onChange={ this.change } cols="10" rows="3"></textarea>
        <select name="selectValue" value={ this.state.selectValue } onChange={ this.change }>
          <option value="ys">亚瑟</option>
          <option value="dj">妲己</option>
          <option value="dw">典韦</option>
        </select>
        <input name="checkbox" type="checkbox" checked={ this.state.checkbox } onChange={ this.change } />

        <button onClick={() => this.setState({
          value: ''
        })}>11</button>
      </div>
    )
  }
}

非受控组件

  1. 借助于 ref,使用原生 DOM 方式来获取表单元素值

  2. ref 的作用:获取 DOM 和组件

  3. 非受控组件使用步骤

    调用 React.createRef()方法创建一个 ref 对象
    将创建好的 ref 对象添加到文本框中
    通过 ref 对象获取到文本框的值
    
import React from 'react'

export default class App extends React.Component {
  constructor () {
    super()
    this.state = {
      val: ''
    }

    // 调用 React.createRef() 方法创建一个 ref 对象
    this.txtRef = React.createRef()
  }

  handleChange = () => {
    // 通过 ref 对象获取到文本框的值
    console.log(this.txtRef.current.value)
  }

  render() {
    return (
      <div>
        {/* 将创建好的 `ref` 对象添加到文本框中 */}
        <input type="text" ref={ this.txtRef } onChange={this.handleChange} />
      </div>
    )
  }
}

2.组件通讯介绍

概念:

组件是独立且封闭的单元,默认情况下,只能使用组件自己的数据。在组件化过程中,我们将一个完整的功能拆分成多个组件,以更好的完成整个应用的功能。而在这个过程中,多个组件之间不可避免的要共享某些数据。为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。这个过程就是组件通讯。

(1)组件中的 props 使用

  1. 组件时封闭的,要接收外部数据应该通过 props 实现
  2. props 的作用:接收传递给组件内部的数据
  3. 传递数据:给组件标签添加属性
  4. 接收数据:函数组件通过参数 props 接收数据,类组件通过 this.props 接收数据
// 类组件

import React from 'react'

export default class App extends React.Component {
  render () {
    return (
      <div>
        <div>{ this.props.name }</div>
      </div>
    )
  }
}

// 函数组件
export default function App (props) {
  return (
    <div>
      <div>{ props.name }</div>
    </div>
  )
}

// 传递数据
ReactDOM.render(<App name="亚瑟" />, document.getElementById('root'))

(2) 组件的 props - 特点

  1. 可以给组件传递任意类型的数据
  2. props 是只读的对象,只能读取属性值,无法修改对象
  3. 注意: 使用类组件时,如果写了构造函数,应该将 props 传递给 super() ,否则,无法在构造函数中获取到 props
// 组件的特点
export default class App extends React.Component {
  constructor (props) {
    //  使用类组件时,如果写了构造函数,应该将 props 传递给 super()
    super(props)
    console.log(props) // {name:'亚瑟',age:10,info:

妲己

}
} render () { // props 是只读的对象,只能读取属性值,无法修改对象 // this.props.name = '百里玄策' return ( <div> {/* 接收任意类型值 */} <div>{ this.props.name }</div> <div>{ this.props.age }</div> <div>{ this.props.info }</div> </div> ) } } // 给组件传值 ReactDOM.render( <App name="亚瑟" age={10} info={<p>妲己</p>} />, document.getElementById('root') )

(3)父组件传递数据给子组件

  1. 父组件提供要传递的 state 数据
  2. 给子组件标签添加属性,值为 state 中的数据
  3. 子组件中共同 props 接收父组件中传递的数据
import React from 'react'

export default class App extends React.Component {
  state = {
    name: '亚瑟'
  }
  render() {
    return (
    // 要传递给子组件的数据
      <Son name={this.state.name}></Son>
    )
  }
}
class Son extends React.Component {
  render() {
    return (
      <div>
      	// 通过 props 来接受父组件传递过来的数据 
        {this.props.name}
      </div>
    )
  }
}

(4) 子组件传递数据给父组件

思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数

  1. 父组件提供一个回调函数(用于接收数据)
  2. 将该函数作为属性的值,传递给子组件
  3. 子组件通过 props 调用回调函数
  4. 将子组件的数据作为参数传递给回调函数
import React from 'react'

export default class App extends React.Component {
  state = {
    name: '亚瑟'
  }

  //  1. 父组件提供一个回调函数
  getSonData = (data) => {
    // 4. 将子组件的数据作为参数传递给回调函数
    console.log('接收到父组件传递过来的数据:' + data)
  }

  render() {
    return (
      {/* 2. 将该函数作为属性的值,传递给子组件 */}
      <Son getSonData={this.getSonData} name={this.state.name}></Son>
    )
  }
}

class Son extends React.Component {
  state = {
    age: 18
  }
  handleClick = () => {
    // 3. 子组件通过 props 调用回调函数
    this.props.getSonData(this.state.age)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>子组件向父组件传值</button>
      </div>
    )
  }
}

(5) 兄弟组件通讯

思想:状态提升

  1. 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
  2. 公共父组件职责:1. 提供共享状态 2. 提供操作共享状态的方法
  3. 要通讯的子组件只需通过 props 接收状态或操作状态的方法
import React from 'react'

export default class App extends React.Component {
  state = {
    name: '亚瑟',
    age: 0
  }

  getSonData = (data) => {
    // 2. 父级将元素赋值给 data
    this.setState({
      age: data
    })
  }

  render() {
    return (
      <div>
        <Son1 getSonData={this.getSonData} name={this.state.name}></Son1>
        {/* 3. 将值传递给另一个子组件 */}
        <Son2 age={ this.state.age }></Son2>
      </div>
    )
  }
}
// 第一个子组件
class Son1 extends React.Component {

  state = {
    age: 18
  }
  handleClick = () => {
    // 1. 通过 props 将值传递给最近的父级
    this.props.getSonData(this.state.age)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>子组件向父组件传值</button>
      </div>
    )
  }
}
// 第二个子组件
class Son2 extends React.Component {
  render() {
    return (
      <div style={{ marginTop: '10px' }}>
        兄弟组件传递的数据: { this.props.age }
      </div>
    )
  }
}

(6)context 使用的步骤:

  • 如果两个组件时远方亲戚,比如嵌套多层,可以使用 Context 实现组件通讯
  • Context 提供了两个组件 Provider 和 Consumer
  • Provider 组件:用来 提供数据
  • Consumer 组件: 用来 消费数据
import React from 'react'
const { Provider, Consumer } = React.createContext()

export default class App extends React.Component {
  state = {
    name: '亚瑟',
    age: 0
  }
  render() {
    return (
      <Provider value={this.state.name}>
        <div>
          <Son1></Son1>
        </div>
      </Provider>
    )
  }
}
// 子组件
class Son1 extends React.Component {
  render() {
    return (
      <div>
        <Son2></Son2>
      </div>
    )
  }
}
// App 的孙子组件  son1的子组件
class Son2 extends React.Component {
  render() {
    return (
      <Consumer>
        {
          data => (
            <div>
              接收祖先节点的数据:{ data }
            </div>
          )
        }
      </Consumer>
    )
  }
}

3. props 深入了解

(1) children 属性

  1. children 属性: 表示组件标签的子节点,当组件标签有子节点时, props 就会有该属性
  2. children 属性: 与普通的 props 一样,值可以是任意值(文本、React 元素、组件、甚至是函数)
// children 属性基本使用
import React from 'react'

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

// 传递 children 属性
ReactDOM.render(
  <App>
    我在等风,也在等你……
  </App>,
  document.getElementById('root')
)

// 传递函数
const handle = () => {
  console.log('你好呀')
}
ReactDOM.render(
  <App>
    {
      handle()
    }
  </App>,
  document.getElementById('root')
)
// 可以传递任何值 甚至也可以传递一个组件

(2)props 校验

  • 安装包 prop-types (yarn add prop-types 或者 npm i props-types)
  • 导入 prop-types 包
  • 使用 组件名.propTypes = {} 来给组件的props添加校验规则
  • 校验规则通过 PropTypes 对象来指定
import React from 'react'
// 导入 props 校验的包
import PropTypes from 'prop-types'

export default class App extends React.Component {
  render () {
    return (
      <div>
        { this.props.arr }
      </div>
    )
  }
}
// 这里表示 App 组件接受了一个 arr 传递过来的必须是一个数组类型的值
App.propTypes = {
  arr: PropTypes.array
}

(3) props 约束规格

  1. 常见类型:array、bool、func、number、object、string
  2. React 元素类型:element
  3. 必填项:isRequired
  4. 特定结构的对象:shape({ })
    详细配置: 使用 PropTypes 进行类型检查

(4)props 默认值

  1. 给 props 设置默认值,在未传入 props 时生效,如果传递了,最终以传递过来的值为准
import React from 'react'
import PropTypes from 'prop-types'

export default class App extends React.Component {
  render () {
    return (
      <div>
        { this.props.num }
      </div>
    )
  }
}
// 接受 num 值 必须为数值类型的
App.propTypes = {
  num: PropTypes.number
}
// 提供默认值为 18
App.defaultProps = {
  num: 18
}

你可能感兴趣的:(js,react)