React入门 - 08(组件拆分&组件传值)

发布时间:2024年01月19日

本章内容

上一节内容我们补充l了在 React使用 JSX语法的一些细节。本节我们继续使用 ”TodoList“ 案例来讲解一下”组件拆分与组件传值“

父组件向子组件传递数据

  • 打开一开始我们已经创建好的工程,现在我们用”组件化“的思想去改写 TodoList组件

  • 那我们应该怎么去拆分组件呢?打开入口文件 index.js时,我们可以清楚的看到 TodoList就是被当成一个大组件挂载到 id=”root“的元素上。

在这里插入图片描述

  • 界面运行后的显示内容也是 TodoList组件的所有内容,所以最外层的”大组件“我们知道是谁了,那么我们就可以对这个”大组件“进行拆分.
    在这里插入图片描述

  • 组件拆分好后,我们在 src目录下新增一个 TodoItem.js, 按照之前的学习知识,我们在 TodoItem这个组件里写一些初始化的代码

// TodoItem.js 组件

import React, { Component } from 'react'
class TodoItem extends Component {
  render () {
    return (
      <div>
        我是组件 TodoItem
      </div>
    )
  }
}
export default TodoItem
  • 现在我们试着在 TodoList.js组件中引入 TodoItem.js组件
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem"; // 1、引入 TodoItem 组件

class TodoList extends Component{
  constructor(props) {
    super(props) // ES6 的语法

    this.state = {
      inputValue: '', 
      list: []
    }
  }

  render() {
    return (
      <Fragment>
        <div>
          <input value={this.state.inputValue} onChange={this.changeInputValue.bind(this)} />
          
          <button onClick={this.addListData.bind(this)}> 提交 </button>
        </div>

        <ul>
          {this.state.list.map((item, index) => {
            // 2、将之前循环 list 数据项时创建的 li 标签注释掉,改为使用 ”组件“的形式来编写代码,这部分代码统一封装在 TodoItem 里
            // return (<li key={index} onClick={(this.deleteData.bind(this,index))}> {item} </li>)

            // 3、不渲染 li 标签了,取而代之的是,使用 TodoItem 组件来渲染内容
            return ( <TodoItem></TodoItem>)
          })}
        </ul>
      </Fragment>
    )
  }

  deleteData(index) {
    const list = [...this.state.list]
    list.splice(index, 1)
    this.setState({
      list: list
    })

  }

  addListData() {
    this.setState({
      list: [...this.state.list, this.state.inputValue]
    })
    this.setState({
      inputValue: ''
    })
  }

  changeInputValue(e) {
    this.setState({
      inputValue: e.target.value
    })
  }
}

export default TodoList
  • 运行一下代码,我们会发现有了效果,也没有报错(有一个让添加 key的警告,我们后续再解决)。但我们发现列表显示的内容并不是我们输入框输入的内容,而是组件 TodoItem里的内容
    在这里插入图片描述

  • 那怎么样才能将输入框的数据传到组件 TodoItem里并正确显示呢?这就要使用到”组件间传值“的知识点嘞

  • 如图所示,实际开发过程中,我们会将复杂的界面拆分成一个”组件树“。组件间存在着各种关系(父子、祖先、相邻等)。而在我们本章案例里的 TodoListTodoItem属于父子关系
    在这里插入图片描述

  • React中,父组件可以通过”属性“的形式向子组件进行传递数据。所以如果 TodoList要将 input输入框的数据传递给 子组件 TodoItem,可以直接定义一个 TodoItem的任意属性,然后通过这个属性进行传值

import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";

class TodoList extends Component{
  constructor(props) {
    super(props) // ES6 的语法

    this.state = {
      inputValue: '', 
      list: []
    }
  }

  render() {
    return (
      <Fragment>
        <div>
          <input value={this.state.inputValue} onChange={this.changeInputValue.bind(this)} />
          
          <button onClick={this.addListData.bind(this)}> 提交 </button>
        </div>

        <ul>
          {this.state.list.map((item, index) => {
            // 在 map 方法中,回调函数的第一个“形参”即为列表(数组)的“每一项 item”,我们又规定了回调函数返回的内容就是这个“每一项 item”。
            // 所以,我们把“每一项 item”起名为 content,并以“属性”的形式传给“子组件 TodoItem”
            return ( <TodoItem content={item}></TodoItem>)
          })}
        </ul>
      </Fragment>
    )
  }

  deleteData(index) {
    const list = [...this.state.list]
    list.splice(index, 1)
    this.setState({
      list: list
    })

  }

  addListData() {
    this.setState({
      list: [...this.state.list, this.state.inputValue]
    })
    this.setState({
      inputValue: ''
    })
  }

  changeInputValue(e) {
    this.setState({
      inputValue: e.target.value
    })
  }
}

export default TodoList
  • 相应的,在 React中,子组件可以通过 this.props.属性的形式来接收父组件传递的数据
import React, { Component } from 'react'

class TodoItem extends Component {
  render () {
    return (
      <div>
        {/* 子组件可以通过 this.props.属性 的形式来接收父组件传递的数据 */}
        {this.props.content}
      </div>
    )
  }
}

export default TodoItem
  • 接着我们再次运行界面,发现输入框输入啥内容提交后,界面就相应的显示其内容数据
    在这里插入图片描述

子组件向父组件传递数据

  • 紧着着上面的代码,我们要接着实现”当点击列表中的某项内容时,该内容从列表中删除“

  • 首先按照需求,我们应该在列表项上绑定一个点击事件。如今的列表项已经被拆成了”小组件“ TodoItem, 所以我们要打开 TodoItem.js文件,去给相应的元素绑定点击事件

import React, { Component } from 'react'

class TodoItem extends Component {
  render () {
    return (
      // 1、绑定点击事件
      <div onClick={this.handleClick.bind(this)}>
        {this.props.content}
      </div>
    )
  }

  // 2、点击事件的逻辑放在 handleClick 方法中
  handleClick() {

  }
}

export default TodoItem
  • ”点击事件“绑定后,我们继续分析以下问题
1、需要确定点击的是列表的哪一项---------可以通过 map 的 index 来确定点击哪一项,并传给 TodoItem 组件

2、通过 index 知道点击的是哪一项后,就要考虑怎么把该项从列表中删除-------子组件TodoItem 的某项被点击时,实质上是将父组件TodoList的”list 数据某项删除“。在父组件中,已经定义了一个删除的方法 ”deleteData“,那么我们可以把这个方法通过属性传值方式传给子组件 TodoItem ,然后子组件自己触发”点击事件“的方法中就可以直接调用父组件传递过来的”删除方法“
  • 按照这个思路,我们来编写代码
// TodoList.js 组件
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";
class TodoList extends Component{
  constructor(props) {
    super(props) // ES6 的语法

    this.state = {
      inputValue: '', 
      list: []
    }
  }

  render() {
    return (
      <Fragment>
        <div>
          <input value={this.state.inputValue} onChange={this.changeInputValue.bind(this)} />
          
          <button onClick={this.addListData.bind(this)}> 提交 </button>
        </div>

        <ul>
          {this.state.list.map((item, index) => {
            // 1、传递 item 给子组件用于内容渲染
            // 2、传递 index 给子组件,让子组件触发自身的删除事件时,知道是哪一项被删除
            // 3、传递 deleteData 方法给子组件,让子组件触发自身的删除事件时进行调用
            return ( <TodoItem content={item} index={index} deleteFn={this.deleteData.bind(this)}></TodoItem>)
          })}
        </ul>
      </Fragment>
    )
  }

  deleteData(index) {
    const list = [...this.state.list]
    list.splice(index, 1)
    this.setState({
      list: list
    })

  }

  addListData() {
    this.setState({
      list: [...this.state.list, this.state.inputValue]
    })
    this.setState({
      inputValue: ''
    })
  }

  changeInputValue(e) {
    this.setState({
      inputValue: e.target.value
    })
  }
}
export default TodoList




// TodoItem.js 组件
import React, { Component } from 'react'
class TodoItem extends Component {
  render () {
    return (
      <div onClick={this.handleClick.bind(this)}>
        {this.props.content}
      </div>
    )
  }

  handleClick() {
    // 4、调用从父组件中传递过来的删除方法,传入删除项的 index 
    this.props.deleteFn(this.props.index)
  }
}
export default TodoItem
  • 运行界面,发现删除功能完美实现

到此,本章内容结束!

文章来源:https://blog.csdn.net/qq_37600506/article/details/135694586
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。