2-react-组件

144 阅读5分钟

1. 组件布局实例

| header |

| 首页 | | Footer |

// App
import Home from './components/Home'
import List from './components/List'

function App() {
  return (
    <List />
  )
}

export default App
// Home
import Layout from './Layout'

function Home() {
  return (
    <Layout>
      <p>当前是home界面</p>
    </Layout>
  )
}

export default Home
// List
import Layout from './Layout'

function List() {
  return (
    <Layout>
      <p>当前是List界面</p>
    </Layout>
  )
}

export default List
// Header
function Header() {
  return (
    <>
      <div className={'header'}>Header组件</div>
    </>
  )
}

export default Header
// Footer
function Footer() {
  return (
    <>
      <div className={'footer'}>Footer组件</div>
    </>
  )
}

export default Footer
// Layout
/**
 * 当前组件的作用就是将 header 与  footer 显示出来,同时中的 main 内容空出来
 * 将来我们传入什么样的 JSX 那么 main 里就显示什么样的 DOM 
 */
import Header from './Header'
import Footer from './Footer'

function Layout(props) {
  return (
    <>
      <Header />
      <div className="main">
        {props.children}
      </div>
      <Footer />
    </>
  )
}

export default Layout

2. 组件状态

  • 组件状态: 状态就数据,因此组件状态指的就是某一个组件自己的数据
  • 数据驱动 DOM:当我们修改某一个数据的时候,界面上的DOM中数据展示也会自动更新
import React, { Component } from 'react'

class Header extends Component {
  // 在类组件当中默认就存在一个 state 属性,它是一个对象,可以用于保存当前组件的数据
  // 之后还可以通过 setState 方法来修改数据的值,最后修改之后结状态会自动展示在 DOM 界面上
  state = {
    name: 'zce',
    age: 40
  }
  handler = () => {
    // 在 react 当中是不能够直接来修改 state 值的
    // this.state.name = 'zoe'
    this.setState({
      name: 'zoe'
    })
  }
  render() {
    return (
      <>
        {this.state.name}
        {this.state.age}
        <button onClick={this.handler}>点击</button>
      </>
    )
  }
}

export default Header 

3. setState使用

  1. setState 是异步函数
    1. 可以使用async与await来解决setState异步执行的问题
    2. 调用 setState的时候可以传入回调函数,在它里面就可以使用修改之后的数据
  2. setState 在使用的时候除了可以传入对象之外还能够传入一个函数
    1. 函数会进行多次执行
  3. setState 在使用的时候既可以传入函数,也可以传入对象,且都是有不同的点的
    1. 对象会进行合并
class Header extends Component {
  state = {
    name: 'zce',
    age: 40,
    count: 0
  }

  handler = () => {
    handler = async() => {
    // 第一种 async await 解决异步
    await this.setState({
      name: 'zoe'
    })
      console.log(this.state.name, 22222)
    }
    // 第二种 回调函数
      this.setState({
      name: 'zoe'
    }, () => {
      console.log(this.state.name, 22222)
    })

    // setState传入函数
    this.setState((state) => ({
       count: state.count + 1
    }))
    // setState传入对象
    this.setState({
      count: this.state.count + 1
    })

  }
  
   render() {
    return (
      <>
        <div>
          {this.state.name}
          {this.state.age}
        </div>
        <hr />
        <div>
          <span>{this.state.count}</span>
          <button onClick={this.handler}>点击</button>
        </div>
      </>
    )
  }

4. 单向数据流

1. 何为单向数据流动
单向数据流的设计原则要求我们将不同组件之前需要共享的数据都定义在上层
2. 单向数据流动如何修改
3. 特点
   1. 单向数据流动,自顶向下,从父组件传到子组件
   2. 基于单向数据流动,要求我们将共享的数据定义在上层组件
   3. 子组件通过调用父组件传递过来的方法可以更改数据
   4. 当数据发生更改之后,React 会重新渲染组件树 
// 父组件
class App extends Component {

  // 在类组件当中就可以使用 state 定义状态
  state = {
    name: 'zce',
    age: 40
  }

  // 定义状态的更新方法, 当前外只负责定义,在想要修改数据的地方会进行调用
  handler = ({ name, age }) => {
    this.setState({ name, age })
  }

  render() {
    return (
      <div>
        单向数据流
        <C1 {...this.state} change={this.handler} />
      </div>
    )
  }
}

// 子组件
import React from 'react'

function C3(props) {
  console.log(props)
  return (
    <div>
      C3组件
      <button onClick={() => { props.change({ name: 'zoe', age: 100 }) }}>点击修改数据</button>
    </div>
  )
}

export default C3

5. 受控表单值绑定与更新

  • react表单分为两种
  1. 受控表单
    表单中所有的数据全部由react来进行管理,此时表单元素中的值全部存放在state中,所有表单元素里的数据都需要从state中获取
  2. 非受控表单
    不常见,不受react管理,通过DOM进行管理
  • 受控表单值绑定与数据同步
  1. 将 state数据绑定给表单的value属性
  2. 修改数据有两种方法
    1. 行内操作法,在行内定义方法,绑定onChange方法,在内部通过ev.target.value获取此时表单的内容,
    2. 通过箭头函数传递ev参数,内部为this.setState({数据名:ev.target.value})
  • 函数操作,必须给表单定义name属性,并且属性值要与绑定的数据相同,利用ev.target.name返回的属性名作为函数操作的属性名进行操作,数据依旧是ev.target.value绑定时如果属性值是动态变化的,那么用中括号进行包裹

  • 细节
    如果表单想要绑定数据但是不需要更改,只想展示
    设置readOnly
    设置defaultValue = {绑定的数据}

class App extends Component {
  state = {
    name: 'zs',
    age: 18,
    test: 'test'
  }
  handler = (ev) => {
    const prop = ev.target.name
    this.setState({
      [prop]: ev.target.value
    })
  }
  handler2 = (ev) => {
    this.setState({
      age: ev.target.value
    })
  }
  render() {
    return (
      <div>
        // 第二种 多个参数 一起修改
        <input name="name" value={this.state.name} onChange={this.handler} />
        // 第一种 绑定方法
        <input value={this.state.age} onChange={this.handler2} />
        // 第三种行内修改
        <input value={this.state.age} onChange={(ev) => {this.setState({age: ev.target.value})}} />
        <input value={this.state.test} readOnly />
        <input deafaultValue={this.state.test}  />
      </div>
    )
  }
}

6. 受控表单之下拉菜单

给select标签绑定value属性,属性动态绑定state属性中的属性,值必须和选项option中的value相同

class App extends Component {
  state = {
    obj: 'java'
  }
  render() {
    return (
      <div>
        <select value={this.state.obj} onChange={(ev) => {this.setState({obj: ev.target.value})}}>
          <option value='大前端'>大前端</option>
          <option value='java'>java</option>
          <option value='python'>python</option>
        </select>
        <hr />
        <button onClick={() => { console.log(this.state.obj)}}>点击</button>
      </div>
    )
  }
}

7. 受控表单单选框

  • 通过defaultChecked布尔值进行判断是否默认选中
  • 通过onChange进行改变
class App extends Component {
  state = {
    sex: '女'
  }
  render() {
    return (
      <div>
        <input type='radio' onChange={(ev) => {this.setState({sex: ev.target.value})}} name='sex' value='男' defaultChecked={this.state.sex === '男'} />男
        <input type='radio' onChange={(ev) => {this.setState({sex: ev.target.value})}} name='sex' value='女' defaultChecked={this.state.sex === '女'} />女
        <hr />
        <button onClick={() => {console.log(this.state.sex)}}>点击</button>
      </div>
    )
  }
}

8. 受控表单 复选框

  • 创建保存数据的对象,渲染到界面上
  • 通过onChange方法进行操作
  • 提交数据时可以自行定义
  • 选框中存在checked属性,可以通过ev.target.checked获取
class App extends Component {
  state = {
    name: 'zs',
    age: 19
  }
  hobbies = [
    {
      id: 1,
      name: 'vue',
      isChecked: true
    },
    {
      id: 2,
      name: 'react',
      isChecked: false
    },
    {
      id: 3,
      name: 'angular',
      isChecked: false
    }
  ]
  handler = (index, ev) => {
    this.hobbies[index].isChecked = ev.target.checked
  }
  submit = (ev) => {
    let ret = this.hobbies.filter(item => item.isChecked).map(data => data.id)
    ret = {
      ...this.state, ret
    }
    console.log(ret)
    ev.preventDefault()
  }
  render() {
    return (
      <form onSubmit={(ev) => {this.submit(ev)}}>
        {this.hobbies.map((item, index) => {
          return (
            <label key={item.id}>
              <input type='checkbox' onChange={this.handler.bind(this, index)} defaultChecked={item.isChecked} />{item.name}
            </label>
          )
        })}
        <hr />
        <button onClick={() => { console.log(this.hobbies) }}>点击</button>
        <input type='submit' />
      </form>
    )
  }
}

9. 非受控组件

  • 给元素设置ref属性,通过this.refs.属性名进行获取
  • strict报错是因为react严格模式
class App extends Component {
  submit = (ev) => {
    console.log(this.refs.username.value);
    ev.preventDefault()
  }
  render() {
    return (
      <form onSubmit={(ev) => {this.submit(ev)}}>
        <input type='text' ref='username' />
        <hr />
        <input type='submit' />
      </form>
    )
  }
}