react入门系列之todolist组件拆分父子组件传值

todolist组件的拆分

  • 之前我们做的todolist,他只有一个组件。就是App.js组件。
  • 其实我们可以将input框,按钮都拆分成一个组件,每一个li也可以分成一个组件去渲染。
  • 现在我们尝试将每一个li拆成一个组件去渲染。

第一步:在src目录下创建一个item.js

  • 代码如下
import React, {Component, Fragment} from 'react';

class Item extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return(
            <Fragment>
                <div>item</div>
            </Fragment>
        )
    }
}

export default Item

第二步:将item组件引入App.js组件中

  • 将item组件引入App组件之后,将li标签替换掉
  • 代码如下
  • 此时我们每点击一次提交按钮下面就会渲染一个item标签,但是内容一直都是item,因为我们在组件中写死了内容
import React, { Component, Fragment }from 'react';
import Item from './item.js' // 引入item组件

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      inputValue: '',// 用来存储 input框中的 value值。
      list:[] // 用来存储 每一个li的 value值。
    }
  }
  handleInputChange = (e) => {
    this.setState({
      inputValue: e.target.value
    })
    console.log(e.target)
  }
  addList = () => {
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      inputValue: '' // 添加完毕以后清空input框
    })
  }
  deletListItem(index) { // 因为在绑定该方法的时候使用了bind函数,所以这里可以不实用箭头函数去保证this的指向
    console.log(index)
    let list = this.state.list;
    list.splice(index, 1);
    console.log(list)
    this.setState({
      list: [...list]
    })
  }
  render(){
    return (
      <Fragment>
      <div>
        <input
        onChange = { this.handleInputChange }
        value = {this.state.inputValue} 
        />
        <button onClick = { this.addList }>提交</button>
      </div>
      <ul>
        {
          this.state.list.map((item, index) => {
            return(
              <Item></Item> { /** 替换li标签 */ }
            )
          })
        }
      </ul>
      </Fragment>
    );
  }
}
export default App;

第三步:父组件给子组件传值

  • 上一步我们实现了item组件的拆分和引用,但是数据没有同步
  • 我们需要将父组件中inputValue传递给item组件
  • 父组件传值给子组件,是通过属性传值。子组件通过this.props去获取父组件传递值。
  • item.js代码如下
import React, {Component, Fragment} from 'react';

class Item extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return(
            <Fragment>
                <div>{this.props.value}</div> {/**通过this.props来获取父组件传递过来的参数*/}
            </Fragment>
        )
    }
}

export default Item
  • App.js组件代码如下
import React, { Component, Fragment }from 'react';
import Item from './item.js'

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      inputValue: '',// 用来存储 input框中的 value值。
      list:[] // 用来存储 每一个li的 value值。
    }
  }
  handleInputChange = (e) => {
    this.setState({
      inputValue: e.target.value
    })
    console.log(e.target)
  }
  addList = () => {
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      inputValue: '' // 添加完毕以后清空input框
    })
  }
  deletListItem(index) { // 因为在绑定该方法的时候使用了bind函数,所以这里可以不实用箭头函数去保证this的指向
    console.log(index)
    let list = this.state.list;
    list.splice(index, 1);
    console.log(list)
    this.setState({
      list: [...list]
    })
  }
  render(){
    return (
      <Fragment>
      <div>
        <input
        onChange = { this.handleInputChange }
        value = {this.state.inputValue} 
        />
        <button onClick = { this.addList }>提交</button>
      </div>
      <ul>
        {
          this.state.list.map((item, index) => {
            return(

              <Item 
              value={item} 
              deletItem = {this.state.deletListItem}
              ></Item> {/** 通过属性传递给子组件 */}

            )
          })
        }
      </ul>
      </Fragment>
    );
  }
}
export default App;

第四步:子组件给父组件传值

  • 上一步通过父组件传值给子组件,我们解决了增加的功能,让item的value能同步input提交的数据
  • 现在我们需要完成删除的功能,删除我们需要将item的key值传递给父组件,让他删除list数组中对应的元素
  • 如何达到效果呢,我们还是需要父组件将删除的方法传递给子组件,再在子组件中去执行他
  • App.js代码如下
import React, { Component, Fragment }from 'react';
import Item from './item.js'

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      inputValue: '',// 用来存储 input框中的 value值。
      list:[] // 用来存储 每一个li的 value值。
    }
  }
  handleInputChange = (e) => {
    this.setState({
      inputValue: e.target.value
    })
    console.log(e.target)
  }
  addList = () => {
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      inputValue: '' // 添加完毕以后清空input框
    })
  }
  deletListItem = (index) => { // 因为在绑定该方法的时候使用了bind函数,所以这里可以不实用箭头函数去保证this的指向
    console.log(index)
    let list = this.state.list;
    list.splice(index, 1);
    console.log(list)
    this.setState({
      list: [...list]
    })
  }
  render(){
    return (
      <Fragment>
      <div>
        <input
        onChange = { this.handleInputChange }
        value = {this.state.inputValue} 
        />
        <button onClick = { this.addList }>提交</button>
      </div>
      <ul>
        {
          this.state.list.map((item, index) => {
            return(

              <Item 
              value = {item} 
              index = {index}
              deletItem = {this.deletListItem}
              ></Item>

            )
          })
        }
      </ul>
      </Fragment>
    );
  }
}
export default App;
  • item.js代码如下
import React, {Component, Fragment} from 'react';

class Item extends Component {
    constructor(props){
        super(props);
    }
    deletItem = () => {
        this.props.deletItem(this.props.index)
        console.log(this.props.index)
    }
    render(){
        return(
            <Fragment>
                <div
                onClick = {this.deletItem}
                >
                {this.props.value}
                </div>
            </Fragment>
        )
    }
}

export default Item

总结

  • 通过以上几步我们以及将li拆分成一个组件了。
  • 但是在父组件传递给子组件函数的时候,需要注意一点,如果你所传递的函数是箭头函数,可以直接传递就如上面代码一样
  • 如果你所传递的函数是一个非箭头函数,需要通过bind(this)强行将这个函数的this指向父组件,不然在子组件中使用的时候this是指向子组件的,子组件是没有父组件的函数的。
  • 另外这次拆分还有一项警告没有解决index.js:1375 Warning: Each child in a list should have a unique "key" prop.
  • 下次更新
posted @ 2019-08-16 18:23  Byhua  阅读(323)  评论(0编辑  收藏  举报