1、组件通讯-父到子
class Father extends React.Component {
constructor(props) {
super(props)
// 组件的状态是私有的,别的组件是用不了
this.state = {
msg: '哈哈'
}
}
render() {
return (
<div>
我是父组件
<Son msg={this.state.msg} name="zs" age="18" />
</div>
)
}
}
// 需求: 在子组件中如何使用父组件的数据
// 1. 父组件通过自定义的属性把值传递给子组件
// 2. 子组件通过props属性可以获取到所有父组件传递过来的数据
class Son extends React.Component {
// props就有所有父组件传递过来的数据
constructor(props) {
super(props)
}
render() {
console.log(this.props)
return (
<div>
我是子组件-----
{this.props.name} ----
{this.props.msg}
</div>
)
}
}
ReactDOM.render(<Father />, document.getElementById('app'))
2、组件通讯-子到父
class Father extends React.Component {
render() {
return (
<div style={{ width: 400, height: 400, backgroundColor: 'pink' }}>
这是父组件
{/* 2. 父组件把方法传递给子组件 */}
<Son getData={this.getData} />
</div>
)
}
//1: 父组件提供一个方法
getData(msg) {
console.log(msg)
console.log('我执行吗')
}
}
class Son extends React.Component {
constructor(props) {
// 子组件通过props来接收父组件传递过来的方法
super(props)
this.state = {
msg: '哈哈'
}
}
render() {
return (
<div style={{ width: 200, height: 100, backgroundColor: 'green' }}>
<p>{this.state.msg}</p>
<button onClick={this.sendData}>给父组件传递数据</button>
</div>
)
}
sendData = () => {
// 4. 给父组件传递数据
let { getData } = this.props
getData(this.state.msg)
}
}
ReactDOM.render(<Father />, document.getElementById('app'))
3、组件通讯-非父子
// 对于多个组件需要共享的数据,应该把这个数据存放到他们公共的父组件中。状态提升
// 始终保持数据是单向数据流。
// 单向数据流
// 状态提升
4、评论列表-基本功能
class Comment extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [
{ id: 1, name: '张三', content: '沙发' },
{ id: 2, name: '李四', content: '板凳' },
{ id: 3, name: '王五', content: '卖瓜子' }
],
index: 3
}
}
render() {
return (
<div>
<h1>评论案例</h1>
<CommentForm add={this.add} />
<hr />
{/* 1. 父组件把评论列表数据传递给了子组件 */}
<CommentList list={this.state.list} />
</div>
)
}
// 添加评论的方法
add = (name, content) => {
this.state.list.push({
id: ++this.state.index,
name,
content
})
this.setState(this.state)
}
}
class CommentForm extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
content: ''
}
}
render() {
return (
<div className="form">
<input
type="text"
value={this.state.name}
onChange={this.handleChange}
name="name"
/>
<br />
<textarea
name="content"
value={this.state.content}
onChange={this.handleChange}
cols="30"
rows="5"
/>
<br />
<button onClick={this.clickFn}>添加</button>
</div>
)
}
clickFn = () => {
// 调用父组件传递过来的方法
let { add } = this.props
add(this.state.name, this.state.content)
// 清空表单
this.setState({
name: '',
content: ''
})
}
handleChange = e => {
let { name, value } = e.target
this.setState({
[name]: value
})
}
}
class CommentList extends React.Component {
constructor(props) {
super(props)
}
render() {
// 2. 子组件通过props可以获取到父组件传递过来的数据
let { list } = this.props
return (
<div className="list">
<ul>
{list.map(item => (
<li key={item.id}>
<h3>
评论人:
{item.name}
</h3>
<p>
评论内容:
{item.content}
</p>
</li>
))}
</ul>
</div>
)
}
}
ReactDOM.render(<Comment />, document.getElementById('app'))
5、react中的children属性
class Modal extends React.Component {
render() {
let { title, children } = this.props
// 通过props.children就能够获取到组件的子元素
return (
<div>
<h3>{title}</h3>
<div>{children}</div>
</div>
)
}
}
// vue 中 slot插槽
ReactDOM.render(
<div>
<Modal title="提示">你是否要退出本系统?</Modal>
<Modal title="温馨提示">是确定要删除这条记录吗?</Modal>
<Modal title="警告">这是一个提示的消息</Modal>
</div>,
document.getElementById('app')
)
6、react中发送请求-axios
class App extends React.Component {
render() {
return (
<div>
<button onClick={this.clickFn}>获取所有的书籍</button>
<button onClick={this.add}>添加书籍</button>
</div>
)
}
clickFn = async () => {
// 发送axios请求
let res = await axios.get('http://localhost:9999/getBookList')
console.log(res.data)
}
add = async () => {
console.log('11')
// 发送请求,添加书籍
let res = await axios.post('http://localhost:9999/addBook', {
name: '你不知道的js',
desc: 'js程序员应该好好读一下'
})
console.log(res)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
7、fetch的使用
class App extends React.Component {
render() {
return (
<div>
<button onClick={this.getAll}>获取所有的书籍</button>
<button onClick={this.add}>添加书籍</button>
<button onClick={this.getInfo}>获取书籍详情</button>
</div>
)
}
getAll = () => {
// 发送一个get请求,获取所有的书籍
// fetch是window的一个方法,fetch是一个全局方法,可以直接使用
// fetch: 返回的是promise对象
fetch('http://localhost:9999/getBookList')
.then(res => {
// res是一个promise对象,表示请求的结果
// res获取到仅仅是响应的结果,还不是我们想要的json
// 还需要对res.json()才表示把响应结果转成json,返回的额是promise
return res.json()
})
.then(data => {
console.log(data)
})
}
getInfo = async () => {
let res = await fetch('http://localhost:9999/getBookInfo?id=1')
let data = await res.json()
console.log(data)
}
add = async () => {
// fetch发送post请求
// 参数1: 请求的url地址
// 参数2: 配置对象
let res = await fetch('http://localhost:9999/addBook', {
method: 'POST',
headers: {
// 用于指定请求的数据类型
// 'content-type': 'application/x-www-form-urlencoded'
'content-type': 'application/json'
},
body: JSON.stringify({
name: '测试',
desc: '测试一下内容'
})
})
let data = await res.json()
console.log(data)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
8、图书馆管理案例
class Book extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [],
name: '',
desc: '',
id: ''
}
}
getBookList = async () => {
// 发送ajax请求,获取到所有的书籍的数据,存到list中
let res = await fetch('http://localhost:9999/getBookList')
let data = await res.json()
let { status, list } = data
if (status === 200) {
this.setState({
list
})
}
}
// 组件挂载好了的时候会触发
componentDidMount() {
this.getBookList()
}
delBook = async (id, e) => {
// 组件默认行为
e.preventDefault()
//1. 获取到了id值
//2. 使用fetch发送请求,删除一条数据,
//3. 成功了,需要重新渲染页面
if (confirm('你是否要删除这条记录')) {
let res = await fetch(`http://localhost:9999/deleteBook?id=${id}`)
let data = await res.json()
if (data.status === 200) {
// 删除成功了
this.getBookList()
}
}
}
handleChange = e => {
let { name, value } = e.target
this.setState({
[name]: value
})
}
save = async () => {
let { id, name, desc } = this.state
let url = null
let params = {
name,
desc
}
if (id) {
url = 'http://localhost:9999/editBook'
params.id = id
} else {
url = 'http://localhost:9999/addBook'
}
// 就是新增的操作
let res = await fetch(url, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(params)
})
let data = await res.json()
let { status } = data
if (status === 200) {
// 重新渲染
this.getBookList()
// 清空表单数据
this.setState({
name: '',
desc: '',
id: ''
})
}
}
editBook = (book, e) => {
// 需要把书籍的信息回显到表单里面
let { id, name, desc } = book
e.preventDefault()
// 数据回显
this.setState({
name,
desc,
id
})
}
render() {
let { list } = this.state
return (
<div className="container">
<div className="form">
书名:
<input
type="text"
value={this.state.name}
onChange={this.handleChange}
name="name"
/>
描述:
<input
type="text"
name="desc"
value={this.state.desc}
onChange={this.handleChange}
/>
<button onClick={this.save}>保存</button>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>书名</th>
<th>描述</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{list.map((item, index) => (
<tr key={item.id}>
<td>{index + 1}</td>
<td>{item.name}</td>
<td>{item.desc}</td>
<td>
<a href="#" onClick={this.delBook.bind(this, item.id)}>
删除
</a>
|
<a href="#" onClick={this.editBook.bind(this, item)}>
修改
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
}
ReactDOM.render(<Book />, document.getElementById('app'))
9、react-create-app
// npx create-react-app my-app
// npm i create-react-app -g
// create-react-app my-app
(1)index.css
.container {
width: 600px;
}
table {
margin-top: 30px;
border: 1px solid blue;
border-collapse: collapse;
width: 100%;
}
table th,
table td {
border: 1px solid blue;
height: 50px;
line-height: 50px;
text-align: center;
}
(2)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="app"></div>
<script src="lib/react.development.js"></script>
<script src="lib/react-dom.development.js"></script>
<script src="lib/babel.min.js"></script>
<script src="lib/axios.js"></script>
<script type="text/babel" src="08-图书管理案例.js"></script>
</body>
</html>
(3)package-lock.json
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"axios": {
"version": "0.18.0",
"resolved": "http://registry.npm.taobao.org/axios/download/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": {
"follow-redirects": "^1.3.0",
"is-buffer": "^1.1.5"
}
},
"debug": {
"version": "3.1.0",
"resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"requires": {
"ms": "2.0.0"
}
},
"follow-redirects": {
"version": "1.5.8",
"resolved": "http://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.5.8.tgz",
"integrity": "sha1-Hb/hPkWtlp+BPobADlKW9SXIhaE=",
"requires": {
"debug": "=3.1.0"
}
},
"is-buffer": {
"version": "1.1.6",
"resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz",
"integrity": "sha1-76ouqdqg16suoTqXsritUf776L4="
},
"ms": {
"version": "2.0.0",
"resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
}
10、react-demo
10.1、components
(1)Home.jsx
import React from 'react'
export default class Home extends React.Component {
render() {
return <div>这是home组件</div>
}
}
(2)Login.jsx
import React from 'react'
export default class Login extends React.Component {
render() {
return <div>这是Login组件</div>
}
}
(3)User.jsx
import React from 'react'
export default class User extends React.Component {
render() {
return <div>这是User组件</div>
}
}
10.2、App.jsx
// react-router-dom的详解
import React from 'react'
import Home from './components/Home.jsx'
import User from './components/User.jsx'
import Login from './components/Login.jsx'
import { HashRouter, Link, Route, Switch } from 'react-router-dom'
class App extends React.Component {
render() {
// HashRouter和BrowserRouter都是核心的路由容器
// HashRouter通过锚点来实现的,路径带了#
// BrowserRouter通过H5的history模式实现,路径不带#
// 路由匹配规则相关的组件有俩
// Route: 表示一个匹配规则
// Switch: 开关,
return (
<HashRouter>
<div>
<ul>
<li>
<Link to="/home">首页</Link>
</li>
<li>
<Link to="/user">用户管理</Link>
</li>
<li>
<Link to="/login">登录</Link>
</li>
</ul>
{/* Switch : 使用Switch把一组route包裹起来,保证只显示一个组件 */}
{/* 配置路由规则 一个路径会对应一个组件 */}
<Switch>
<Route path="/home" component={Home} />
<Route path="/user" component={User} />
<Route path="/login" component={Login} />
</Switch>
</div>
</HashRouter>
)
}
}
export default App
10.3、App-基本使用.jsx
// 根组件
import React from 'react'
import Home from './components/Home.jsx'
import User from './components/User.jsx'
import Login from './components/Login.jsx'
import { HashRouter, Route, Link } from 'react-router-dom'
// 如何在react项目中使用react-router
// 1. 需要安装react-router-dom包 npm i react-router-dom
// 2. 需要引入一些组件
class App extends React.Component {
render() {
// HashRouter:整个路由容器,将来配置路由,是一定要有一个HashRouter
// Link : 相当于vue中 router-link 配置路由的连接,最终会渲染成一个a标签
// Route: 配置路由规则
return (
<HashRouter>
<div>
<ul>
<li>
<Link to="/home">首页</Link>
</li>
<li>
<Link to="/user">用户管理</Link>
</li>
<li>
<Link to="/login">登录</Link>
</li>
</ul>
{/* 配置路由规则 一个路径会对应一个组件 */}
<Route path="/home" component={Home} />
<Route path="/user" component={User} />
<Route path="/login" component={Login} />
</div>
</HashRouter>
)
}
}
export default App
10.3、index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.jsx'
ReactDOM.render(<App />, document.getElementById('root'))
11、脚手架基本使用
11.1、components
(1)Comment.css
.container {
width: 800px;
margin: 0 auto;
}
(2)Comment.jsx
import React from 'react'
import CommentForm from './CommentForm.jsx'
import CommentList from './CommentList.jsx'
import './Comment.css'
class Comment extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [
{ id: 1, name: '张三', content: '沙发' },
{ id: 2, name: '李四', content: '板凳' },
{ id: 3, name: '王五', content: '卖瓜子' }
],
index: 3
}
}
render() {
return (
<div className="container">
<h1>评论案例</h1>
<CommentForm add={this.add} />
<hr />
{/* 1. 父组件把评论列表数据传递给了子组件 */}
<CommentList list={this.state.list} />
</div>
)
}
// 添加评论的方法
add = (name, content) => {
this.state.list.push({
id: ++this.state.index,
name,
content
})
this.setState(this.state)
}
}
export default Comment
(3)CommentForm.jsx
import React from 'react'
class CommentForm extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
content: ''
}
}
render() {
return (
<div className="form">
<input
type="text"
value={this.state.name}
onChange={this.handleChange}
name="name"
/>
<br />
<textarea
name="content"
value={this.state.content}
onChange={this.handleChange}
cols="30"
rows="5"
/>
<br />
<button onClick={this.clickFn}>添加</button>
</div>
)
}
clickFn = () => {
// 调用父组件传递过来的方法
let { add } = this.props
add(this.state.name, this.state.content)
// 清空表单
this.setState({
name: '',
content: ''
})
}
handleChange = e => {
let { name, value } = e.target
this.setState({
[name]: value
})
}
}
export default CommentForm
(4)CommentList.jsx
import React from 'react'
class CommentList extends React.Component {
render() {
// 2. 子组件通过props可以获取到父组件传递过来的数据
let { list } = this.props
return (
<div className="list">
<ul>
{list.map(item => (
<li key={item.id}>
<h3>
评论人:
{item.name}
</h3>
<p>
评论内容:
{item.content}
</p>
</li>
))}
</ul>
</div>
)
}
}
// 导出组件
export default CommentList
11.2、App.jsx
// jsx就表示一个react组件, jsx仅仅是后缀不一样 jsx的作用和js的作用完全一样
// 有些编辑器,看到jsx文件,提供一些高亮,提示等等
// 定义一个根组件
import React from 'react'
import Comment from './components/Comment.jsx'
class App extends React.Component {
render() {
return <Comment />
}
}
// 导出根组件
export default App
11.3、index.css
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
11.4、index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
// 导入根组件react的根组件,我们的内容都应该写到App里面
import App from './App.jsx'
// 渲染了根组件
ReactDOM.render(<App />, document.getElementById('root'))