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

本文详细介绍了在React中如何通过组件拆分和属性传递实现父组件向子组件以及子组件向父组件的数据交换,以TodoList和TodoItem组件为例,展示了如何通过props进行数据传递和事件处理。
摘要由CSDN通过智能技术生成

本章内容

上一节内容我们补充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
  • 运行界面,发现删除功能完美实现

到此,本章内容结束!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值