react项目配置(类组件、函数式组件)

react项目详解

  • 类组件
    • 1、事件绑定
    • 2、setState
    • 3、组件通讯
    • 4、插槽
    • 5、样式隔离
    • 6、ref 的使用 (相当于函数式组件中的 useRef)
  • 函数式组件
    • 7、定义变量,修改变量
    • 8、useEffect 副作用函数
    • 9、useMemo
    • 10、useCallback
    • 11、useRef (相当于类组件的 createRef)
    • 12、高阶组件(相当于vue中的mixins)

类组件

1、事件绑定

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();

2、setState

  1. setState 是浅合并 (Object.asign), 所以在更新 state 状态时,如果是对象,一定要展开再合并新的数据
state = {
	obj: {
		a: 1,
		b: 2,
		c: 3
	}
}
setState({
	obj: {
		...this.state.obj,
		b: 5
	}
})
  1. setState 在修改 list 数组的时候,如果是 React.Component 可是直接在数据的基础上修改,如果是 React.PureComponent ,就只能深拷贝一份数组再进行修改,因为 PureComponent 对比的是地址值
  2. 多次 setState render只会走一次
  3. 在类组件中 React.Component 下,setState 走一次, 就会render 一次页面更新,所以尽量使用 React.PureComponent
  4. setState 是异步的,取值要在第二个参数里面
setState({
	msg: "修改msg的值"
}, () => {
	this.state.msg  // 取值
})

3、组件通讯

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    // 校验对象
}

4、插槽

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>
}

5、样式隔离

创建 xxx.module.scss, 在jsx引入

// 在js中
import style from "./xxx.module.scss"
render() {
	return <div className={ style.box }>
		111
	</div>
}
// css中
.box{
	.....
} 

6、ref 的使用 (相当于函数式组件中的 useRef)

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 在函数的第一个参数接受

7、定义变量,修改变量

import { useState } from "react"
let [msg, setMsg] = useState('')  // 定义msg变量
// 修改msg变量
function changeMsg() {
	setMsg('修改msg变量的值')
}

return <div>
	{ msg }  // 使用变量
	<button onClick={() => changeMsg()}>修改变量</button>
</div>

8、useEffect 副作用函数

1、不传第二个参数 = componentDidMount 和 componentDidUpdate
2、第二个参数传空数组 = componentDidMount
3、第二个参数数组里面放某个数据 = watch 监听
4、第一个参数函数体里面返回值是一个方法 = componentDidUnMount

useEffect(function() {}, [])

9、useMemo

useMemo 类似于 vue 中的计算属性, 第二个参数和 useEffect 的参数用法是一样的

// 1、定义常量的时候可以用 useMemo 包裹一下,表示只在创建的时候创建一次, 更新的时候就不创建了
const computedObj = useMemo(function() {
   return {
        name: "张三",
        age: 18
    }
}, [])

// 2、当做计算属性来使用,依赖写在第二个参数的数组里面
const computedObj = useMemo(() => msg + ":" + text, [msg, text])  // 表示只有 msg 和 text 两个变量改变的时候,useMemo 才会重新运行

10、useCallback

包裹方法使用的hook,第二个参数和 useMemo、useEffect 规则是一样的

11、useRef (相当于类组件的 createRef)

import { useRef, useEffect } from "react"
const div1 = useRef()
useEffect(() => {
	console.log(div1.current)  // 获取dom节点
}, [])
return <div>
	<div ref={div1}>111</div>
</div>

12、高阶组件(相当于vue中的mixins)

高阶组件就相当于 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)  // 只用高阶组件包装一下再暴露出去就可以了

你可能感兴趣的:(react.js,前端,javascript)