class App extends React.Component {
// 定义事件
handleClick1(val, e) {
// 阻止默认行为
e.preventDefault();
//阻止冒泡
e.stopPropagation();
console.log(val, e);
}
// 定义事件第二种方式
handleClick2(val3, e) {
console.log(val3);
}
render() {
return (
<div className={style.App}>
<button onClick={this.handleClick1.bind(this, "传参数")}>事件绑定</button>
<button onClick={(e) => this.handleClick2(11, e)}>事件绑定第二中方式</button>
</div>
);
}
}
注意:react中阻止冒泡和默认行为和原生是一样的 e.preventDefault(); e.stopPropagation();
state = {
obj: {
a: 1,
b: 2,
c: 3
}
}
setState({
obj: {
...this.state.obj,
b: 5
}
})
setState({
msg: "修改msg的值"
}, () => {
this.state.msg // 取值
})
react 中父组件传值给子组件 和 子组件传值给父组件,都是通过 props 来实现的
父组件给子组件传值,父组件给子组件传递属性即可
// 父组件中
render() {
return <div>
<Son name="父传值给子"></Son>
</div>
}
// 子组件中接值
this.props.name
子组件传值给父组件,父组件给子组件传递方法即可
// 父组件中
getChildValue(val) {
console.log("父组件拿到子组件的值", val)
}
render() {
return <div>
<Son onGetChildValue={this.getChildValue.bind(this)}></Son>
</div>
}
// 子组件中
handle() {
this.props.onGetChildValue("子组件的值传给父组件") // 子组件拿到父组件传过来的方法直接调用,把值传过去
}
render() {
return <div>
<button onClick={this.handle.bind(this)}>点击给父组件值</button>
</div>
}
子组件接值验证和默认值的定义
// props 验证值的类型 和 默认值
Son.propTypes = {
name: (props) => {
if(typeof props.name !== "string") {
return new Error("期望一个字符串")
}
return null
}
}
Son.defaultProps = {
name: "默认值"
}
子组件接值验证借助第三方库
// 1、下载 proptypes
yarn add proptypes
// 2、引用
import propType from "proptypes"
// 子组件接值校验 (使用)
Son.propTypes = {
name: propType.string, // 校验字符串
age: propType.number, // 校验数字
list: propType.array, // 校验数组
obj: propType.object // 校验对象
}
react中的插槽的使用也是 props
// 1、默认插槽
父组件
render() {
return <div>
<Slot>
<div>before</div> // 需要在子组件展示的内容
</Slot>
</div>
}
子组件
render() {
const { children } = this.props
return <div>
{children}
</div>
}
// 2、具名插槽
父组件
render() {
return <div>
<Slot>
<div data-id="before">before</div> // 父组件传过去两处在子组件需要展示的内容
<div data-id="after">after</div>
</Slot>
</div>
}
子组件占位,展示父组件的内容
render() {
// 子组件从 props 得到 父组件传进来的 自定义属性为 data-id, 然后判断展示在不同的位置
const { children } = this.props
let beforeVNode, afterNode
children.forEach(v => {
if("before" === v.props['data-id']) {
beforeVNode = v
}else{
afterNode = v
}
})
return <div>
{beforeVNode} // 虚拟Dom用插值表达式来解析
Slot
{afterNode}
</div>
}
// 3、作用域插槽 (借助的就是子传值给父组件)
父组件
render() {
return <div>
<Slot customClick={(val) => console.log(val)}></Slot>
</div>
}
子组件
render() {
return <div>
<button onClick={() => this.props.customClick(this.state.msg)}>作用域插槽</button>
</div>
}
创建 xxx.module.scss, 在jsx引入
// 在js中
import style from "./xxx.module.scss"
render() {
return <div className={ style.box }>
111
</div>
}
// css中
.box{
.....
}
ref 获取dom
const div1 = React.createRef() // 定义的 div1 和标签中的 ref 的值是一样的
componentDidMount() {
console.log(div1) // 获取 dom
}
render() {
return <div>
<div ref={div1}>111</div>
</div>
}
ref 获取组价实例
const divComponent = React.createRef() // 定义的 divComponent 和标签中的 ref 的值是一样的
componentDidMount() {
console.log(divComponent) // 获取组件实例
}
render() {
return <div>
<Son ref={divComponent}></Son>
</div>
}
1、函数式组件没有生命周期
2、函数式组件没有 this
3、函数式组件通过 hook 来完成各种操作
4、函数式组件本身的函数体相当于 render 函数
5、props 在函数的第一个参数接受
import { useState } from "react"
let [msg, setMsg] = useState('') // 定义msg变量
// 修改msg变量
function changeMsg() {
setMsg('修改msg变量的值')
}
return <div>
{ msg } // 使用变量
<button onClick={() => changeMsg()}>修改变量</button>
</div>
1、不传第二个参数 = componentDidMount 和 componentDidUpdate
2、第二个参数传空数组 = componentDidMount
3、第二个参数数组里面放某个数据 = watch 监听
4、第一个参数函数体里面返回值是一个方法 = componentDidUnMount
useEffect(function() {}, [])
useMemo 类似于 vue 中的计算属性, 第二个参数和 useEffect 的参数用法是一样的
// 1、定义常量的时候可以用 useMemo 包裹一下,表示只在创建的时候创建一次, 更新的时候就不创建了
const computedObj = useMemo(function() {
return {
name: "张三",
age: 18
}
}, [])
// 2、当做计算属性来使用,依赖写在第二个参数的数组里面
const computedObj = useMemo(() => msg + ":" + text, [msg, text]) // 表示只有 msg 和 text 两个变量改变的时候,useMemo 才会重新运行
包裹方法使用的hook,第二个参数和 useMemo、useEffect 规则是一样的
import { useRef, useEffect } from "react"
const div1 = useRef()
useEffect(() => {
console.log(div1.current) // 获取dom节点
}, [])
return <div>
<div ref={div1}>111</div>
</div>
高阶组件就相当于 vue 中的 mixins 混入, 说白了就是往使用高阶组件的组件的 props 里面 放一些公共的属性和方法
在 utils 里面建一个高阶组件 HigherOrderComponent.jsx
// HigherOrderComponent.jsx
import { useState } from "react"
// 高阶组件的封装
export default function HeightComponent(Component) { // 暴露出去一个方法
return function Heightsa(props) { // 返回一个方法
// 高阶组件封装的属性值(每个使用高阶组件的组件都可以使用)
const [heightVal] = useState("高阶函数封装的属性")
// 高阶组件封装的方法(每个使用高阶组件的组件都可以使用)
const heightMethods = () => {
console.log("高阶函数封装的方法");
}
return <>
// 把传进来的组件加上高阶组件包装之后的 props 返回出去,使用这个高阶组件的组件就有了上面的属性和方法
<Component {...props} heightVal={heightVal} heightMethods={heightMethods}></Component>
</>
}
}
组件的使用者
import HeightComponent from "../utils/HigherOrderComponent.jsx"
const App = (props) => {
const { heightVal, heightMethods } = props // 拿到了高阶组件的属性和方法了
return <div>
App
</div>
}
export default HeightComponent(App) // 只用高阶组件包装一下再暴露出去就可以了