父给子传值
// 父组件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="输入关键词点击搜索" />
<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>
)
}
}