React-2 -- setState、组件间通信、组件的生命周期

    技术2023-06-17  64

    React-2

    1. 重点内容回顾2. 学习目标3. 学习内容3.1 state 和 setState3.2 组件间通信跨组件通信 context - 扩展 3.3 组件的生命周期3.3.1生命周期演变1)之前版本(React 16.3 之前)2)现在使用*挂载阶段**更新阶段**卸载阶段**错误处理* 3.4 生命周期函数详解3.5 受控组件3.6 todoList 初实现 预习内容

    1. 重点内容回顾

    JSX 注意事项 必须有,且只有一个顶层的包含元素 - React.FragmentJSX 不是html,很多属性在编写时不一样 classNamestyle 列表渲染时,必须有 key 值在 jsx 所有标签必须闭合组件的首字母一定大写,标签一定要小写 类组件 组件类必须继承 React.Component组件类必须有 render 方法 事件 大小写问题this 问题 props 和 state props 父组件传递过来的参数state 组件自身状态

    2. 学习目标

    掌握 setState 的各种使用情况掌握 React 组件间通信掌握 React 组件的生命周期掌握受控组件的使用

    3. 学习内容

    3.1 state 和 setState

    setState(updater, [callback]) updater: 更新数据 FUNCTION/OBJECTcallback: 更新成功后的回调 FUNCTION异步:react通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能浅合并 Objecr.assign()

    3.2 组件间通信

    在 React.js 中,数据是从上自下流动(传递)的,也就是一个父组件可以把它的 state / props 通过 props 传递给它的子组件,但是子组件不能修改 props - React.js 是单向数据流,如果子组件需要修改父组件状态(数据),是通过回调函数方式来完成的。

    父级向子级通信 把数据添加子组件的属性中,然后子组件中从props属性中,获取父级传递过来的数据

    子级向父级通信 在父级中定义相关的数据操作方法(或其他回调), 把该方法传递给子级,在子级中调用该 方法父级传递消息

    案例:完善好友列表

    跨组件通信 context - 扩展

    React.createContext(defaultValue); { Consumer, Provider } = createContext(defaultValue)Context.Provider 在父组件调用 Provider 传递数据 value 要传递的数据 接收数据 class.contextType = Context;static contextType = Context; this.context; Context.Consumer <Consumer> {(props)=>{console.log(props); return <div></div> }} </Consumer> 注意在使用不熟练时,最好不要再项目中使用 context,context一般给第 三方库使用 import React,{Component} from 'react'; import FriendList from './FriendList'; import {Provider} from './context' /* 类组件: 1. 组件类必须继承 **React.Component** 2. 组件类必须有 **render** 方法 3. render 方法的 return 后,定义组件的内容 ps:记得导出 跨组件通信 context - 扩展 Provider */ // 组件通信 class App extends Component { // 2. 第二版本---------------------------------- // state = { // info:"啦啦啦" // } render(){ return ( // Provider传递数据 <Provider value={{ //Provider标签 想给谁传,就把谁包起来 info:"啦啦啦" }}> <div> <FriendList /> </div> </Provider>) } // 1. 第一版本---------------------------------- // state = { // name:"鸡胸肉", // hobby:"打豆豆" // } // changeValue = (newName)=>{ // this.setState({name:newName}) // } // render(){ // let {hobby} = this.state; // return (<div> // <p>{this.state.name}</p> // <FriendList // hobby = {hobby} // changeValue = {this.changeValue} // /> // </div>) // } } export default App;

    context.js:

    import {createContext} from "react" let context = createContext(); let {Consumer,Provider} = context; export default context export {Consumer,Provider}

    3.3 组件的生命周期

    所谓的生命周期就是指某个事物从开始到结束的各个阶段,当然在 React.js 中指的是组件从创建到销毁的过程,React.js 在这个过程中的不同阶段调用的函数,通过这些函数,我们可以更加精确的对组件进行控制,前面我们一直在使用的 render 函数其实就是组件生命周期渲染阶段执行的函数

    3.3.1生命周期演变

    1)之前版本(React 16.3 之前)

    挂载阶段 constructorcomponentWillMount (该方法即将过时,在新代码中应避免使用)rendercomponentDidMount 更新阶段 父组件更新引起组件更新 componentWillReceiveProps(nextProps) (该方法即将过时,在新代码中应避免使用)shouldComponentUpdate(nextProps, nextState)componentWillUpdate(nextProps, nextState)rendercomponentDidUpdate(prevProps, prevState) 组件自身更新 shouldComponentUpdatecomponentWillUpdate (该方法即将过时,在新代码中应避免使用)rendercomponentDidUpdate 卸载阶段 componentWillUnmount

    2)现在使用

    挂载阶段

    当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

    constructor

    static getDerivedStateFromProps(props, state) - 注意 this 问题(为第三个参数),需要写return

    render

    componentDidMount


    更新阶段

    当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

    父组件更新引起组件更新 static getDerivedStateFromProps(props, state)shouldComponentUpdate()componentWillUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate() 组件自身更新 shouldComponentUpdate()componentWillUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
    卸载阶段

    当组件从 DOM 中移除时会调用如下方法:

    componentWillUnmount
    错误处理

    当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:

    static getDerivedStateFromError()componentDidCatch(error, info) 参考连接:生命周期图谱

    3.4 生命周期函数详解

    1. constructor(props)

    constructor(props)

    类的构造函数,也是组件初始化函数,一般情况下,我们会在这个阶段做 一些初始化的工作

    通过给 this.state 赋值对象来初始化内部 state。处理事件绑定函数的 this。为事件处理函数绑定实例

    在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state:

    constructor(props) { super(props); // 不要在这里调用 this.setState() this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); }

    只能在构造函数中直接为 this.state 赋值。如需在其他方法中赋值,你应使用 this.setState() 替代。

    2. render()

    render()

    render 方法是 Class 组件必须实现的方法

    render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。如需与浏览器进行交互,请在 componentDidMount() 或其他生命周期方法中执行你的操作。保持 render() 为纯函数,可以使组件更容易思考。注意 如果 shouldComponentUpdate()返回 false,则不会调用 render()。

    3. static getDerivedStateFromProps(props, state) (不常用)

    static getDerivedStateFromProps(props, state)

    该方法会在 render 方法之前调用,无论是挂载阶段还是更新阶段,它的存在只有一个目的:让组件在 props 变化时更新 state

    4. componentDidMount()

    componentDidMount()

    在组件挂载后(render 的内容插入 DOM 树中)调用。通常在这个阶段,我们可以:

    操作 DOM 节点发送请求

    5. shouldComponentUpdate(nextProps, nextState) (不常用)

    shouldComponentUpdate(nextProps, nextState)

    发生在更新阶段,getDerivedStateFromProps 之后,render 之前,该函数会返回一个布尔值,决定了后续是否执行 render,首次渲染不会调用该函数

    6. getSnapshotBeforeUpdate(prevProps, prevState) (不常用)

    getSnapshotBeforeUpdate(prevProps, prevState)

    render --> 虚拟DOM --> 真实DOM --> 挂载到文档 该方法在 render() 之后,但是在输出到 DOM 之前执行,用来获取渲染之前的快照。 当我们想在当前一次更新前获取上次的 DOM 状态,可以在这里进行处理,该函数的返回值将作为参数传递给下个生命周期函数componentDidUpdate

    该函数并不常用。

    7. componentDidUpdate()

    componentDidUpdate(prevProps, prevState, snapshot)

    该函数会在 DOM 更新后立即调用,首次渲染不会调用该方法。我们可以在这个函数中对渲染后的 DOM 进行操作

    componentDidUpdate(prevProps) { // 典型用法(不要忘记比较 props): if (this.props.userID !== prevProps.userID) { this.fetchData(this.props.userID); } }

    8. componentWillUnmount()

    componentWillUnmount() 该方法会在组件卸载及销毁前调用,我们可以在这里做一些清理工作,如:组件内的定时器、未完成的请求等componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

    9. 错误处理

    当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法

    static getDerivedStateFromError()componentDidCatch()

    3.5 受控组件

    受控组件:类似于Vue的双向数据绑定,数据和视图之间可以相互影响 非受控组件:类似于单向数据流,只可以数据改变视图,我们不需要同步 value 值(defaultValue,defaultChecked)

    import React,{Component} from 'react'; /* 受控组件 defaultValue : 非受控 */ class App extends Component { state = { info:"这是值" } render(){ let {info} = this.state; return ( <div> {/* 单向绑定 */} {/* <input type="text" defaultValue={info} /> <input type="text" defaultValue={info} /> <input type="text" defaultValue={info} /> */} {/* 受控组件:类似于Vue的双向数据绑定 数据和视图之间可以相互影响 非受控组件:类似于单向数据流 只可以数据改变视图 */} <input type="text" value={info} onChange={({target})=>{ this.setState({ info:target.value }) }} /> <button onClick={()=>{ console.log(info); }}>点一点</button> </div>) } } export default App;

    3.6 todoList 初实现

    预习内容

    掌握React其他 API 使用:PureComponent、ref、children、dangerouslySetInnerHTML、key 掌握函数式组件及常见 hooks 的使用 可以独立开发基于Hooks 或 Component 的 todoList 应用

    Processed: 0.013, SQL: 10