第一部分:类组件和函数组件
// 第一步:导入react import React from "react"; // 第二步:创建构造函数ChildTest继承 React.Component class ChildTest extends React.Component { render(){ return <div> <h2>我是class类组件</h2> </div> } } export default ChildTest
/* 函数组件:16.8前-无状态组件 16.8之后-react hooks */ function App(){ return ( <div> <h2>App</h2> </div> ) } export default App
第二部分:组件嵌套
import { Component } from "react"; // import React from "react"; class Child extends Component{ render(){ return <div>Child</div> } } class Navbar extends Component { render(){ return ( <div>Navbar<Child></Child></div> ) } } function Swiper(){ return <div>Swiper</div> } // 箭头函数this指向外部导 const Tabbar=()=>{ return <div>Swiper</div> } class App extends Component { render(){ return ( <div> <Navbar></Navbar> <Swiper></Swiper> <Tabbar></Tabbar> </div> ) } } export default App
第一步:新建/css/01-index.css
.active{ background-color: blue; } #myapp{ background-color: pink; }
第二步:导入组件
// import { Component } from "react"; import React from "react"; import './css/01-index.css' //导入css模块 webpack的支持 // 因为react感觉每个组件都是一个独立的整体 export default class App extends React.Component { render(){ let obj = { backgroundColor:"yellow", fontSize:"30px" } return ( <div> app组件 <h3 style={obj}>111111111</h3> <h3 style={
{backgroundColor:"red"}}>2222222222222</h3> {/* 以前的class现在的className*/} <h3 className="active">css样式测试class类名</h3> <h3 id="myapp">id选择器</h3> {/* 以前的for现在的htmlFor */} <label htmlFor="username">用户名:</label> <input type="text" id="username"/> </div> ) } }
第四部分:事件绑定与this指向
// import { Component } from "react"; import React from "react"; // 推荐行内风格 export default class App extends React.Component { state={ a:100 } render(){ return ( <div> <input/> <button onClick={()=>{ console.log(this,this.state.a)//100__有this }}>点我1</button> <button onClick={this.handleClick2}>点我2</button> <button onClick={this.handleClick3}>点我3</button> <button onClick={()=>{this.handleClick4()}}>点我4</button> </div> ) } handleClick2=()=>{ console.log(this,this.state.a,2)//100__有this } handleClick3(){ console.log(this,3) //没有this //this.handleClick3.bind(this)可改变this指向 } handleClick4=()=>{ console.log(this,this.state.a,4)//100__有this } }
第五部分:ref和非受控表单组件(获取)dom)
-
在state在表单元素中作为表单元素value值(控制表单元素值)
-
添加表单元素change事件,设置state表单元素的值(控制值的变化)
import React from "react"; export default class Ref extends React.Component { myref =React.createRef() render(){ return ( <div> <h2>ref</h2> {/* <input ref="mytext"/> */} <input ref={this.myref}/> <button onClick={()=>{this.handle()}}>点我</button> </div> ) } handle=()=>{ // console.log(this.refs.mytext)///之前的写作方法 console.log(this.myref.current) //现在获得dom(input) } }
第六部分:受控表单组件
借助非受控组件ref,使用原生DOM获取表单元素值的方法
import React from "react"; export default class App extends React.Component { state={ mgs:10 } render(){ return ( <div> <h2>Controlled</h2> <input onChange={this.handle} type="text" value={this.state.mgs}/> </div> ) } handle=(e)=>{ this.setState({ mgs:e.target.value }) console.log(this.state.mgs) ///此时获得mgs中等数据是表单数据,但打印延迟数据 } }
第七部分:setState
-
setState() 是异步更新数据的
-
注意:使用该语法时,后面的 setState() 不要依赖于前面的 setState()
1. 当你调用 setState 的时候,React.js 并不会马上修改 state (为什么) 2. 而是把这个对象放到一个更新队列里面 3. 稍后才会从队列当中把新的状态提取出来合并到 state 当中,然后再触发组件更新。
可以多次调用 setState() ,只会触发一次重新渲染
this.state = { count: 1 }
this.setState({
count: this.state.count + 1
})
console.log(this.state.count) // 1
在使用 React.js 的时候,并不需要担心多次进行 setState
会带来性能问题。
推荐语法
-
推荐:使用
setState((preState) => {})
语法 -
参数preState: React.js 会把上一个
setState
的结果传入这个函数
this.setState((preState) => {
return {
count: preState.count + 1
}
})
console.log(this.state.count) // 1
第二个参数
-
场景:在状态更新(页面完成重新渲染)后立即执行某个操作
-
语法:
setState(updater[, callback])
this.setState(
(state) => ({}),
() => {console.log('这个回调函数会在状态更新后立即执行')}
)
例如
this.setState(
(state, props) => {},
() => {
document.title = '更新state后的标题:' + this.state.count
}
)
注意:不要直接修改state中的值,必须通过this.setState()
方法进行修改
class App extends React.Component {
state = {
count: 1
}
handleClick() {
this.setState({
count: this.state.count + 1
})
console.log(this.state.count)//在此处打印只能获取到数据更改前的值
}
render() {
return (
<div>
<p>次数: {this.state.count}</p>
<button onClick={this.handleClick.bind(this)}>点我+1</button>
</div>
)
}
}
<!-- setState是一个异步还是一个同步 -->
+ 18以前
- 使用react事件触发就是一个异步
- 不使用react的事件(原生)触发就是一个同步
+ 18及以后+++++都是一个异步
class App extends React.Component {
state = {
count: 1
}
handle=()=>{
this.setState(
(preState)=>{
// console.log(preState) //获取更新之前的值
return {
count:this.state.count+1
}
},
()=>{
console.log(this.state.count)//在此箭头函数中能获取到state中数据更新的最新值
}
)
}
render() {
return (
<div>
<p>次数: {this.state.count}</p>
<button onClick={this.handleClick.bind(this)}>点我+1</button>
</div>
)
}
}
第八部分:组件通讯
第一种:函数组件通讯
在父组件中
<Hello name="jack" age={19} />
在子组件中
function Hello(props) {
console.log(props)
return (
<div>接收到数据:{props.name}</div>
)
}
第二种:类组件通讯
在父组件中
<Hello name="jack" age={19} />
在子组件中
class Hello extends React.Component {
render() {
return (
<div>接收到的数据:{this.props.age}</div>
)
}
}
子传父
思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。
-
父组件提供一个回调函数(用于接收数据)
-
将该函数作为属性的值,传递给子组件
-
子组件通过 props 调用回调函数
-
将子组件的数据作为参数传递给回调函数
父组件提供函数并且传递给字符串
//msg为接收到子组件传过来的数据
class Parent extends React.Component {
getChildMsg = (msg) => {
console.log('接收到子组件数据', msg)
}
render() {
return (
<div>
子组件:<Child getMsg={this.getChildMsg} />
</div>
)
}
}
子组件接收函数并且调用
class Child extends React.Component {
state = { childMsg: 'React' }
handleClick = () => {
this.props.getMsg(this.state.childMsg)
}
return (
<button onClick={this.handleClick}>点我,给父组件传递数据</button>
)
}
****
第九部分:兄弟组件
第一步:创建公共js文件
import React from "react";
export const {Provider,Consumer} = React.createContext()
第二步:使用 Provider 组件作为父节点。
import React from "react";
import {Provider} from "./index.js";
class App extends React.Component {
render(){
//设置 value 属性,表示要传递的数据。
return <Provider value="pink">
<child1></child1>
<child2></child2>
</Provider>
}
}
export default App;
第三步:调用 Consumer 组件接收数据。
import { Consumer } from "./index.js";
const Child1= (props)=>{
return (
<div>
<h2>props{props.children}</h2>//类似插槽
<Consumer>
{(data)=>{
return <span>data接收到的参数==={data}===</span>
}}
</Consumer>
</div>
)
}
export default Child1
第十部分:props校验
目的:校验接收的props的数据类型,增加组件的健壮性
使用步骤
-
导入 prop-types 包
-
使用组件名.propTypes = {} 来给组件的props添加校验规则
-
校验规则通过 PropTypes 对象来指定
import PropTypes from 'prop-types'
function App(props) {
return (
<h1>Hi, {props.colors}</h1>
)
}
App.propTypes = {
// 约定colors属性为array类型
// 如果类型不对,则报出明确错误,便于分析错误原因
colors: PropTypes.array
}
约束规则
-
常见类型:array、bool、func、number、object、string
-
React元素类型:element
-
必填项:isRequired
-
特定结构的对象:shape({})
// 常见类型
optionalFunc: PropTypes.func,
// 必选
requiredFunc: PropTypes.func.isRequired,
// 特定结构的对象
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
props默认值
场景:分页组件 每页显示条数
作用:给 props 设置默认值,在未传入 props 时生效
function App(props) {
return (
<div>
此处展示props的默认值:{props.pageSize}
</div>
)
}
// 设置默认值
App.defaultProps = {
pageSize: 10
}
// 不传入pageSize属性
<App />