网站安全体系建设方案,云服务器学生优惠,网络及it维护外包,有没有免费的crm系统软件1.目标
能够实用props接收数据 能够实现父子组件之间的通讯 能够实现兄弟组件之间的通讯 能够给组件添加props校验 能够说出生命周期常用的钩子函数 能够知道高阶组件的作用
2.目录
组件通讯介绍 组件的props 组件通讯的三种方式 Context props深入 组件的生命周期 Render-p…1.目标
能够实用props接收数据 能够实现父子组件之间的通讯 能够实现兄弟组件之间的通讯 能够给组件添加props校验 能够说出生命周期常用的钩子函数 能够知道高阶组件的作用
2.目录
组件通讯介绍 组件的props 组件通讯的三种方式 Context props深入 组件的生命周期 Render-props和高阶组件
3.react tool 安装 React Devloper Tools 插件
4.组件通讯介绍
组件是独立且封闭的单元默认情况下只能使用组件自己的数据。在组件化过程中我们将一个完整 的功能拆分成多个组件以更好的完成整个应用的功能。而在这个过程中多个组件之间不可避免的要 共享数据。为了实现这些功能就需要打破组件的独立封闭性让其与外界沟通。这个过程就是组件通 讯。
5.组件的props
A. 组件是封闭的要接收外部数据应该通过props来实现 B. props的作用接收传递给组件的数据 C. 传递数据给组件标签添加属性 D. 接收数据函数组件通过参数props接收数据类组件通过this.props接收数据
function Hello(props) {return div接收到的值{props.name}/div;
}class Hello1 extends React.Component {constructor() {super();}render() {return div接收到的值{this.props.name}/div;}
}ReactDOM.createRoot(document.getElementById(root)).render(React.StrictModeHello name张三/HelloHello1 name李四/Hello1/React.StrictMode
);5.1 特点
A. 可以给组件传递任意类型的数据 B. props是只读的对象只能读取属性的值无法修改对象 C. 注意使用类组件时如果写了构造函数应该将props传递给super(),否则无法再构造函数中获取 到props!
class Hello2 extends React.Component {constructor(props) {//推荐将props传递给父类构造函数 super(props)}
render() {return (div接收到的数据{this.props.age}/div)}
}
ReactDOM.render(Hello2 namerose age{22}/Hello2,document.getElementById(root));5.2 其他类型数据
class Hello2 extends React.Component {constructor() {//推荐将props传递给父类构造函数super()}
render() {return (div接收到的数据{this.props.age} {this.props.tag}/div)
}
ReactDOM.render(Hello2 namerose age{22} colors{[red, yellow, blue]}
fn{() { console.log(这是一个函数) }} tag{p这是一个P标签/p}/Hello2,
document.getElementById(root));6.组件通讯的三种方式
组件之间的通讯分为3种 A. 父组件-子组件 B. 子组件-父组件 C. 兄弟组件
6.1 父组件传递数据给子组件
A. 父组件提供要传递的state数据 B. 给子组件标签添加属性值为state中的数据 C. 子组件中通过props接收父组件中传递的数据
.parent {background-color: skyblue;height: 200px;
}.child {background-color: pink;height: 100px;
}// 父组件给子组件传值
class Parent61 extends React.Component {state { lastName: 练 };render() {return (div classNameparent父组件{this.state.lastName 凝}Child61 lastName道济/Child61/div);}
}const Child61 (props) {return (div classNamechild子组件接受到父组件传的值{props.lastName}/div);
};ReactDOM.createRoot(document.getElementById(root)).render(Parent61/Parent61
);6.2 子组件传递数据给父组件
思路利用回调函数父组件提供回调子组件调用将要传递的数据作为回调函数的参数。 A. 父组件提供一个回调函数用于接收数据 B. 将该函数作为属性的值传递给子组件 C. 子组件通过props调用回调函数 D. 将子组件的数据作为参数传递给回调函数 注意回调函数里面的this指向问题
// 6.2
class Parent extends React.Component {state {sonMsg: ,};getChildMsg (msg) {this.setState({sonMsg: msg,});};render() {return (div子组件传过来的值{this.state.sonMsg}Child getMsg{this.getChildMsg}/Child/div);}
}class Child extends React.Component {state {sonMsg: react牛掰,};sendMsg () {this.props.getMsg(this.state.sonMsg);};render() {return (divbutton onClick{this.sendMsg}向父组件传值/button/div);}
}ReactDOM.createRoot(document.getElementById(root)).render(Parent/Parent);6.3 兄弟传值
A. 将共享数据提升到最近的公共父组件中由公共父组件管理这个状态 B. 思想状态提升 C. 公共父组件职责1.提供共享状态 2.提供操作共享状态的方法 D. 要通过的子组件只需通过props接收状态或操作状态的方法
class Parent63 extends React.Component {// 提供公共状态state {count: 0,};// 提供修改状态的方法onIncrement () {this.setState({count: this.state.count 1,});};render() {return (divChild631 count{this.state.count}/Child631Child632 onIncrement{this.onIncrement}/Child632/div);}
}
const Child631 (props) {return div计数器{props.count}/div;
};
const Child632 (props) {return button onClick{() props.onIncrement()}1/button;
};ReactDOM.createRoot(document.getElementById(root)).render(Parent63/Parent63
);6.4 context
思考App组件要传递数据给Child组件该如何处理 A. 处理方式使用props一层层组件往下传递繁琐 B. 更好的姿势使用Context C. 作用跨组件传递数据比如主题、语言等
6.4.1 使用步骤
A. 调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件。 B.使用Provider组件作为父节点 C. 设置value属性表示要传递的数据 D. 调用Consumer组件传递数据
.app64{
background-color: red;
padding:20px;
}
.node64{
background-color: yellow;
padding:20px;
}
.subNode64{
background-color: green;
padding:20px;
}
.child64{
background-color: purple;
padding: 20px;
}// 创建context得到两个组件
const { Provider, Consumer } React.createContext();class App64 extends React.Component {render() {return (divProvider value{hello}div classNameapp64Node64/Node64/div/Provider/div);}
}const Node64 () {return (div classNamenode64SubNode64/SubNode64/div);
};const SubNode64 () {return (div classNamesubNode64Child64/Child64/div);
};const Child64 () {return (div classNamechild64Consumer{(data) span我是子节点{data}/span}/Consumer/div);
};ReactDOM.createRoot(document.getElementById(root)).render(App64/App64);6.4.2 总结
A. 如果两个组件是远方亲戚比如嵌套多层可以使用Context实现组件通讯 B. Context提供了两个组件Provider和Consumer C. Provider组件用来提供数据 D. Consumer组件用来消费数据
7.props深入
7.1 children属性
A. children属性表示组件标签的子节点。当组件标签有子节点时props就会有该属性 B. children属性与普通的props一样值可以是任意值文本、React元素、组件甚至是函数
const App1 (props) {console.log(props);return (divh1组件标签的子节点/h1{props.children}/div);
};ReactDOM.createRoot(document.getElementById(root)).render(App1p我是p标签/p{/* {() {console.log(123);}} */}/App1
);7.2 props校验
A. 对于组件来说props是外来的无法保证组件使用者传入什么格式的数据 B. 如果传入的数据格式不对可能会导致组件内部报错 C. 关键问题组件的使用者不知道明确的错误原因
function App72(props) {const list props.list;const lis list.map((item, index) li key{index}{item}/li);return ul{lis}/ul;
}ReactDOM.createRoot(document.getElementById(root)).render(App72 list{19}/App72
);D.props校验允许在创建组件的时候就指定props的类型、格式等 E. 作用捕获使用组件时因为props导致的错误给出明确的错误提示增加组件的健壮性
7.2.1 使用步骤
A. 安装包prop-types(yarn add prop-types/npm i prop-types) B. 导入prop-types包 C. 使用组件名.propTypes{}来给组件的props添加校验规则 D. 校验规则通过PropTypes对象来指定
import PropTypes from prop-types;
function App721(props) {const list props.list;const lis list.map((item, index) li key{index}{item}/li);return ul{lis}/ul;
}
App721.propTypes {//约定list属性为array类型//如果类型不对则报错明确错误便于分析错误原因list: PropTypes.array,
};ReactDOM.createRoot(document.getElementById(root)).render(App721 list{19}/App721
);7.3 props的默认值
A. 场景分页组件-每页显示条数 B. 作用给props设定默认值在未传入props时生效
class App73 extends React.Component {render() {return (div此处展示props默认值{this.props.age} {this.props.gender}/div);}
}App73.defaultProps {age: 18,gender: 男,
};ReactDOM.createRoot(document.getElementById(root)).render(App73 namezs/App73
);8.组件的生命周期
8.1 组件的生命周期概述
A. 意义组件的生命周期有助于理解组件的运行方式完成更复杂的组件功能分析组件错误原因等 B. 组件的生命周期组件从被创建到挂载到页面中运行再到组件不用时卸载的过程 C. 生命周期的每个阶段总是伴随着一些方法调用这些方法就是生命周期的钩子函数。 D. 钩子函数的作用为开发人员再不同阶段操作组件提供了时机 E. 只有类组件才有生命周期
8.2 生命周期的三个阶段
A. 每个阶段的执行时机 B. 每个阶段钩子函数的执行顺序 C. 每个阶段钩子函数的作用
8.2.1 创建时挂载阶段
A. 执行时机组件创建时页面加载时 B. 执行顺序 constructor:创建组件时最先执行。初始化state和为事件处理程序绑定this render每次组件渲染都会触发渲染ui注意不能调用setState componentDidMount:组件挂载完成DOM渲染后发送网络请求DOM操作
class App821 extends React.Component {constructor(props) {super(props);// 初始化数据this.state {count: 0,};// 主要处理this指向问题console.log(生命周期钩子函数constructor);const title document.getElementById(h1);console.log(constructor中的DOM为 title); // null获取不到DOM}// 进行DOM操作// 发送ajax请求获取远程数据componentDidMount() {const title document.getElementById(h1);console.log(componentDidMount中的DOM为 title); // 获取到了}render() {// 不要在render中调用setState// this.setState({// count: 1,// });console.log(生命周期钩子函数render);return (divh1 idh1统计豆豆被打的次数/h1button打豆豆/button/div);}
}ReactDOM.createRoot(document.getElementById(root)).render(App821/App821);8.2.2 更新时更新阶段
A. 执行时机1.setState() 2.forceUpdate() 3.组件接收到新的props B. 说明以上三者任意一种变化组件就会重新渲染 C. 执行顺序 render():每次组件渲染都会触发渲染UI(在挂载阶段是同一个render) componentDidUpdate():组件更新完成DOM渲染后发送网络请求DOM操作注意如果要 setState()必须放在一个if条件中
class App822 extends React.Component {constructor(props) {super(props);this.state {count: 0,};}handleClick () {this.setState({count: this.state.count 1,});};render() {return (divCounter822 count{this.state.count}/Counter822button onClick{this.handleClick}打豆豆/button/div);}
}class Counter822 extends React.Component {render() {console.log(子组件-生命周期钩子函数render());return (divh1 idtitle打豆豆的数量{this.props.count}/h1/div);}componentDidUpdate(prevProps) {console.log(子组件-生命周期钩子函数componentDidUpdate());//获取domconst title document.getElementById(title);console.log(title.innerHTML);console.log(前一状态的props值,prevProps,当前状态的props值,this.props);}
}ReactDOM.createRoot(document.getElementById(root)).render(App822/App822);8.2.3 卸载时
A.执行时机组件从页面中消失 componentWillUnmount:组件卸载从页面消失执行清理工作
class App823 extends React.Component {constructor(props) {super(props);// 初始化数据this.state {count: 0,};}handleClick () {this.setState({count: this.state.count 1,});};render() {console.log(生命周期钩子函数render());return (div{this.state.count 3 ? (h1豆豆被打死了/h1) : (Count823 count{this.state.count}/Count823)}button onClick{this.handleClick}打豆豆/button/div);}
}
class Count823 extends React.Component {render() {console.log(子组件-生命周期钩子函数render());return h1 idtitle豆豆被打的次数{this.props.count}/h1;}componentDidMount() {console.log(子组件-生命周期钩子函数componentDidMount()); // 创建时钩子函数只在创建时执行一次this.timerId setInterval(() {console.log(定时器正在执行中~~~~~~~~);}, 500);}componentWillUnmount() {console.log(子组件-生命周期钩子函数componentWillUnmount());clearInterval(this.timerId);}
}ReactDOM.createRoot(document.getElementById(root)).render(App823/App823);9.render-props和高阶组件
9.1 react组件复用概述
A. 思考如果两个组件中的部分功能相似或相同该如何处理 B. 处理方式复用相似的功能联想函数封装 C. 复用什么1.state 2.操作state的方法组件状态逻辑 D. 两种方式1.render props模式 2.高阶组件HOC E. 注意这两种方式不是新的API,而是利用React自身特点的编码技巧演化而成的固定模式写法
9.2 render props 模式
9.2.1 思路分析
A. 思路将要复用的state和操作state的方法封装到一个组件中 B. 问题1如何拿到该组件中复用的state C. 在使用组件时添加一个值为函数的prop通过函数参数获取需要组件内部实现 D. 问题2如何渲染任意的 E. 使用该函数的返回值作为要渲染的UI内容需要组件内部实现
9.2.2 使用步骤
A. 创建Mouse组件在组件中提供复用的状态逻辑代码1.状态 2.操作状态的方法 B. 将要复用的状态作为props.render(state)方法的参数暴露到组件外部 C. 使用props.render()的放回置作为要渲染的内容 9.2render_props.js
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}render() {return this.props.render(this.state);}
}
class App92 extends React.Component {render() {return (divh1render props模式/h1Mouserender{(mouse) {return (h1鼠标坐标{mouse.x}:{mouse.y}/h1);}}/Mouse/div);}
}export default App92;
index.js
import App92 from ./92render_props;
ReactDOM.createRoot(document.getElementById(root)).render(App92/App92);9.2.3 mouse组件的复用
A. Mouse组件负责封装复用的状态逻辑代码1.状态 2.操作状态的方法 B. 状态鼠标坐标x,y C. 操作状态的方法鼠标移动事件 D. 传入的render prop负责使用复用的状态来渲染UI结构
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;// 导入图片
import img from ./logo192.png;//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}render() {return this.props.render(this.state);}
}
class App92 extends React.Component {render() {return (divh1render props模式/h1{/* 鼠标位置 */}Mouserender{(mouse) {return (h1鼠标坐标{mouse.x}:{mouse.y}/h1);}}/Mouse{/* 图片 */}Mouserender{(mouse) {return (imgwidth50src{img}alt鼠标图片style{{position: absolute,top: mouse.y,left: mouse.x,cursor: none,}}/img);}}/Mouse/div);}
}export default App92;9.2.4 children代替render属性
A. 注意并不是该模式叫render props就必须使用名为render的prop,实际上可以使用任意名称的prop B. 把prop是一个函数并且告诉组件要渲染什么内容的技术叫做render props模式 C. 推荐使用children代替render属性
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;// 导入图片
import img from ./logo192.png;//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}render() {// return this.props.render(this.state);return this.props.children(this.state);}
}
class App92 extends React.Component {render() {return (divh1render props模式/h1{/* 鼠标位置 */}{/* Mouserender{(mouse) {return (h1鼠标坐标{mouse.x}:{mouse.y}/h1);}}/Mouse */}{/* 图片 */}{/* Mouserender{(mouse) {return (imgwidth50src{img}alt鼠标图片style{{position: absolute,top: mouse.y,left: mouse.x,cursor: none,}}/img);}}/Mouse */}{/* children版本 */}Mouse{(mouse) {return (h1鼠标位置{mouse.x}:{mouse.y}/h1);}}/Mouse{/* Mouse组件复用 */}Mouse{(mouse) {return (imgsrc{img}altreactwidth{100}style{{position: absolute,top: mouse.y - 50,left: mouse.x - 50,}}/img);}}/Mouse/div);}
}export default App92;9.2.5 代码优化
A. 推荐给render props 模式添加props校验 B. 应该在组件卸载时接触mousemove事件绑定
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;// 导入图片
import img from ./logo192.png;//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}render() {// return this.props.render(this.state);return this.props.children(this.state);}// 推荐在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener(mousemove, this.handleMouse);}
}
// 添加校验
Mouse.propTypes {children: PropTypes.func.isRequired,
};class App92 extends React.Component {render() {return (divh1render props模式/h1{/* 鼠标位置 */}{/* Mouserender{(mouse) {return (h1鼠标坐标{mouse.x}:{mouse.y}/h1);}}/Mouse */}{/* 图片 */}{/* Mouserender{(mouse) {return (imgwidth50src{img}alt鼠标图片style{{position: absolute,top: mouse.y,left: mouse.x,cursor: none,}}/img);}}/Mouse */}{/* children版本 */}Mouse{(mouse) {return (h1鼠标位置{mouse.x}:{mouse.y}/h1);}}/Mouse{/* Mouse组件复用 */}Mouse{(mouse) {return (imgsrc{img}altreactwidth{100}style{{position: absolute,top: mouse.y - 50,left: mouse.x - 50,}}/img);}}/Mouse/div);}
}export default App92;9.3 高阶组件
9.3.1 概述
A. 目的:实现状态逻辑复用 B. 采用包装装饰模式比如说手机壳 C. 手机获取保护功能 D. 手机壳提供保护功能 E. 高阶组件就相当于手机壳通过包装组件增强组件功能
9.3.2 思路分析
A. 高阶组件HOC,Higher-Order Component是一个函数接收要包装的组件返回增强后的组件 B. 高阶组件内部创建一个类组件在这个类组件中提供复用的状态逻辑代码通过prop将复用的状态传 递给被包装组件WrappendComponent
9.3.3 使用步骤
A. 创建一个函数名称约定以with开头 B. 指定函数参数参数应该以大写字母开头作为要渲染的组件 C. 在函数内部创建一个类组件提供复用的状态逻辑代码并返回 D. 在该组件中渲染参数组件同时将状态通过prop传递给参数组件 E. 调用该高阶组件传入要增强的组件通过返回值拿到增强后的组件并将其渲染到页面中 9.3 gjzj.js
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;// 导入图片
import img from ./logo192.png;//创建高阶组件
function WithMouse(WrappendComponent) {//该组件提供复用的状态逻辑class Mouse extends React.Component {state {x: 0,y: 0,};handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}//推荐在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener(mousemove, this.handleMouse);}// 渲染被包装的组件并传递复用的状态逻辑render() {return WrappendComponent {...this.state}/WrappendComponent;}}return Mouse;
}// 普通测试
const Position (props) {return (h1【x:{props.x}y:{props.y}】/h1);
};const Img (props) {return (imgsrc{img}alt图片width{50}style{{ position: absolute, top: props.y, left: props.x }}/img);
};// 获取增强后组件
const MousePosition WithMouse(Position);
const MouseImg WithMouse(Img);class App93 extends React.Component {render() {return (div高阶组件MousePosition/MousePositionMouseImg/MouseImg/div);}
}export default App93;import App93 from ./93gjzj;
ReactDOM.createRoot(document.getElementById(root)).render(App93/App93);9.3.4 设置displayName
A. 使用高阶组件存在的问题得到的两个组件名称相同 B. 原因默认情况下React使用组件名称作为displayName C. 解决方式为高阶组件设置displayName便于调试时区分不同的组件 D. displayName的作用用于设置调试信息React Developer Tools信息 E. 设置方式
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;// 导入图片
import img from ./logo192.png;//创建高阶组件
function WithMouse(WrappendComponent) {//该组件提供复用的状态逻辑class Mouse extends React.Component {state {x: 0,y: 0,};handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}//推荐在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener(mousemove, this.handleMouse);}// 渲染被包装的组件并传递复用的状态逻辑render() {return WrappendComponent {...this.state}/WrappendComponent;}}//设置displayMouse.displayName WithMouse${getDisplayName(WrappendComponent)};return Mouse;
}
function getDisplayName(WrappendComponent) {return WrappendComponent.displayName || WrappendComponent.name || Component;
}// 普通测试
const Position (props) {return (h1【x:{props.x}y:{props.y}】/h1);
};const Img (props) {return (imgsrc{img}alt图片width{50}style{{ position: absolute, top: props.y, left: props.x }}/img);
};// 获取增强后组件
const MousePosition WithMouse(Position);
const MouseImg WithMouse(Img);class App93 extends React.Component {render() {return (div高阶组件MousePosition/MousePositionMouseImg/MouseImg/div);}
}export default App93;9.3.5 传递props
A. 问题props丢失 B. 原因高阶组件没有往下传递props C. 解决方式渲染WrappedComponent时将state和this.props一起传递给组件 D. 传递方式
import React from react;
import ReactDOM from react-dom/client;
import PropTypes from prop-types;// 导入图片
import img from ./logo192.png;//创建高阶组件
function WithMouse(WrappendComponent) {//该组件提供复用的状态逻辑class Mouse extends React.Component {state {x: 0,y: 0,};handleMouse (e) {this.setState({x: e.clientX,y: e.clientY,});};// 监听鼠标移动事件componentDidMount() {window.addEventListener(mousemove, this.handleMouse);}//推荐在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener(mousemove, this.handleMouse);}// 渲染被包装的组件并传递复用的状态逻辑render() {return (WrappendComponent {...this.state} {...this.props}/WrappendComponent);}}//设置displayMouse.displayName WithMouse${getDisplayName(WrappendComponent)};return Mouse;
}
function getDisplayName(WrappendComponent) {return WrappendComponent.displayName || WrappendComponent.name || Component;
}// 普通测试
const Position (props) {return (h1【x:{props.x}y:{props.y} {console.log(props)}】/h1);
};const Img (props) {return (imgsrc{img}alt图片width{50}style{{ position: absolute, top: props.y, left: props.x }}/img);
};// 获取增强后组件
const MousePosition WithMouse(Position);
const MouseImg WithMouse(Img);class App93 extends React.Component {render() {return (div高阶组件MousePosition/MousePositionMouseImg/MouseImg/div);}
}export default App93;