【react】react类组件父给子传值、子给父传值、兄弟传值

父给子传值

// 父组件App.jsx
import React, { Component } from 'react'
import './App.css'
import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer'

export default class App extends Component {
  state = {
    todos: [
      {id: '001', name: '吃饭', done: true},
      {id: '002', name: '睡觉', done: true},
      {id: '003', name: '打代码', done: false},
    ]
  }
  render() {
    const {todos} = this.state

    return (
      <div className="todo-container">
        <div className="todo-wrap">
          <Header/>
          {/*给子组件传值*/}
          <List todos={this.state.todos}/>
          <Footer/>
        </div>
      </div>
    )
  }
}
// 子组件1 List.jsx
import React, {Component} from 'react';
import ListItem  from '../ListItem'

export default class List extends Component {
  render() {
    const {todos} = this.props	// 用props接受父组件传过来的数据
    return (
      <ul className="todo-main">
      	// 使用父组件传过来的数据
        {
          todos.map(todo => {
            return (<ListItem key={todo.id} {...todo}/>)
          })
        }
      </ul>
    )
  }
}

子给父传值:利用props接受父给子传的函数体,通过形参的方式将子的数据传给父

// 父组件:App.jsx
import React, { Component } from 'react'
import './App.css'
import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer'

export default class App extends Component {
  state = {
    todos: [
      {id: '001', name: '吃饭', done: true},
      {id: '002', name: '睡觉', done: true},
      {id: '003', name: '打代码', done: false},
      {id: '004', name: '逛街', done: false},
    ]
  }

  // addTodo用于添加一个todo,接受的参数是todo对象
  addTodo = (todoObj) => {
    // todoObj就是子组件header给父传的值
    console.log(todoObj, 'app')
    // 获取原todos
    const {todos} = this.state
    // 在todos的前面追加一个todo
    const newTodos = [todoObj, ...todos]
    // 更新状态,页面才会更新
    this.setState({todos: newTodos})
  }
  
  render() {
    const {todos} = this.state

    return (
      <div className="todo-container">
        <div className="todo-wrap">
          <Header addTodo={this.addTodo}/>
          <List todos={todos}/>
          <Footer/>
        </div>
      </div>
    )
  }
}
// 子组件2:Header.jsx
import React, {Component} from 'react';

export default class Header extends Component {
  handleKeyUp = (event) => {
    // keyCode是键盘上按键的标识
    const {keyCode, target} = event;
    // 13是回车键的标识,按下回车键,获取输入框的值
    if(keyCode !== 13) return
    // 添加的todo名不能为空
    if(target.value.trim() === '') {
      alert('输入不能为空')
      return
    }
    // 子组件给父组件传值
    const todoObj = {
      id: nanoid(),
      name: target.value,
      done: false,
    }
    this.props.addTodo(todoObj)
    // 清空输入值
    target.value = ''
  }
  
  render() {
    return (
      <div>
        <div className="todo-header">
          <input type="text" 
          	placeholder='请输入你的任务名称,按回车键确认' 
          	onKeyUp={this.handleKeyUp} 
          />
        </div>
      </div>
    )
  }
}

兄弟传值:使用发布订阅模式
1、安装pubsub

npm i pubsub

2、使用:PubSub.publish是发布消息,PubSub.subscribe是订阅消息

// 兄弟组件1:search.jsx
import React, { Component } from 'react'
import axios from 'axios'
import PropTypes from 'prop-types'
import PubSub from 'pubsub-js'

export default class Search extends Component {
  static propTypes = {
    updateAppState: PropTypes.func.isRequired,
  }
  
  search = () => {
    // 获取用户的输入
    const {keywordElement: {value}} = this
    // 发送请求前通知app更新状态
    PubSub.publish('atguigu', {isFirst: false, isLoading: true})
    // 发送网络请求
    axios.get(`http://api.github.com/search/users?q=${value}`).then(
      res => {
        // avatar_url  login html-url
        console.log('成功', res)
        // 请求成功后通知List更新状态
        PubSub.publish('atguigu', {isLoading: false, users: res.data.items || []})
      },
      err => {
        // 请求失败后通知app更新状态
        console.log('失败', err)
        PubSub.publish('atguigu', {isLoading: false, err: err.message})
      }
    )
  }
  render() {
    return (
      <div>
        <section className="jumbotron">
          <h3 className="jumbotron-heading">Search Github Users</h3>
          <div>
            {/* 回调函数形式获取ref */}
            <input ref={c => this.keywordElement = c} type="text" placeholder="输入关键词点击搜索" />&nbsp;
            <button onClick={this.search}>Search</button>
          </div>
        </section>
      </div>
    )
  }
}
// 兄弟组件2:List.jsx
import React, { Component } from 'react'
import './index.css'
import PubSub from 'pubsub-js'

export default class Search extends Component {
  state = {
    users: [],
    isFirst: true, // 是否是第一次打开页面
    isLoading: false, // 是否正在加载中
    err: null, // 存储请求相关的错误信息
  }

  componentDidMount() {
    // 订阅消息
    PubSub.subscribe('atguigu', (_, stateObj) => {
      console.log(stateObj, 'stateObj')
      this.setState(stateObj)
    })
  }

  render() {
    // const {users, isFirst, isLoading, err} = this.props
    const {users, isFirst, isLoading, err} = this.state
    return (
      <div className="row">
        {
          isFirst ? <h2>欢迎使用,输入关键字,随后点击搜索</h2> :
          isLoading ? <h2>Loading...</h2> :
          err ? <h2>{err.message}</h2> :
          users.map(userObj => {
            // 函数体
            return(
              <div className="card" key={userObj.id}>
                <a href={userObj.html_url} target="_blank">
                  <img src={userObj.avatar_url} alt="head_portrait" style={{width: '100px'}} />
                </a>
                <p className="card-text">{userObj.login}</p>
              </div>
            )
          })
        }
      </div>
    )
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值