react学习笔记,ReactDOM,react-router-dom
react 学习
1. 下载与安装
下载
npm install -g create-react-app
安装
npx create-react-app xxx 推荐
npm init react-app xxx
yarn create react-app xxx
2. 创建 react 元素 indexjs 文件
import React from "react";
import ReactDOM from "react-dom";
// 1创建react元素const title = React.createElement("h1", null, "1111111hello word");
ReactDOM.render(title, document.getElementById("root"));// 2创建react元素
import React from "react";
import ReactDOM from "react-dom";const title = <h1>helloword</h1>;ReactDOM.render(title, document.getElementById("root"));
3. 类名
class => className
const title =
helloword 1111111111
4. 组件
import React from "react";
import ReactDOM from "react-dom";function Hello() {return <div>111111111111111zujian1</div>;
}const Hello = () => <div>188888888811zujian1</div>;ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
### 组件拆分
index.js
import Hello from './components/Hello'ReactDOM.render(<Hello></Hello>, document.getElementById('root'))
Hello.js
import React from "react";class Hello extends React.Component {render() {return (<div>hello组件</div>)}
}export default Hello
5. 继承
// 继承import React from "react";import ReactDOM from "react-dom";class Hello extends React.Component {render() {return (<div>111111111class继承</div>)}}ReactDOM.render(<Hello></Hello>, document.getElementById('root'))//组件式
//1 Hello.jsimport React from "react";class Hello extends React.Component {render() {return (<div>hello组件</div>)}
}export default Hello//2 index.js
import Hello from './components/Hello'ReactDOM.render(<Hello></Hello>, document.getElementById('root'))
6. 点击事件
class Hello extends React.Component {handOlick() {console.log("点击触发");}render() {return <button onClick={this.handOlick}>点击</button>;}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
function Hello() {function handclick() {console.log("点击触发;1");}return <button onClick={handclick}>点击</button>;
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
7. 阻止默认事件
class Hello extends React.Component {handclick(e) {e.preventDefault(); // 阻止默认跳转 阻止a标签的默认跳转console.log("点击触发了");}render() {return (<a href="http://www.baidu.com" onClick={this.handclick}>跳转</a>);}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
8. state
class Hello extends React.Component {// constructor() {// super()// this.state = {// num: 0// }// }// 简化state = {num: 1,};render() {return <div>state使用 {this.state.num}</div>;}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
9. setState
class Hello extends React.Component {// 简化state = {num: 1,};render() {return (<div><div>state使用 {this.state.num}</div><buttononClick={() => {this.setState({ num: this.state.num + 1 });}}>+1</button></div>);}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
箭头函数;
class Hello extends React.Component {// 简化state = {num: 1,};onIncrement = () => {this.setState({ num: this.state.num + 1 });};render() {return (<div><div>state使用222 {this.state.num}</div>{/* 2强制改变this */}<button onClick={this.onIncrement}>+1</button></div>);}
}
10 改变 this 指向
// p31 强制改变this 用consturctorclass Hello extends React.Component {// 简化// state = {// num: 1// }constructor() {super();this.state = {num: 1,};this.onIncrement = this.onIncrement.bind(this);}onIncrement() {this.setState({ num: this.state.num + 1 });}render() {return (<div><div>state使用222 {this.state.num}</div>{/* 2强制改变this */}<button onClick={this.onIncrement}>+1</button></div>);}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
11. 表单处理
受控组件
// 受控组件class Hello extends React.Component {state = {txt: "",content: "",};handlerChange = (e) => {this.setState({txt: e.target.value,});console.log(e.target.value);console.log(this.state.txt);};handlarComtent = (e) => {this.setState({context: e.target.value,});};render() {return (<div><inputtype="text"value={this.state.txt}onChange={this.handlerChange}></input><textareavalue={this.state.content}onChange={this.handlarComtent}></textarea></div>);}
}
多表单元素优化
// 多表单元素的优化class Hello extends React.Component {state = {txt: "",content: "",};handlerForm = (e) => {const target = e.target;const value = target.type === "checkbox" ? target.cheched : target.value;const name = target.name;this.setState({[name]: value,});console.log(value);console.log(name);console.log(e.target.value);console.log(this.state.txt);};render() {return (<div><inputtype="text"value={this.state.txt}onChange={this.handlerForm}></input><textareavalue={this.state.content}onChange={this.handlerForm}></textarea></div>);}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
非受控组件
非受控组件;class Hello extends React.Component {constructor() {super();this.txtRef = React.createRef();}getTxt = () => {console.log("文本框" + this.txtRef.current.value);};render() {return (<div><input type="text" ref={this.txtRef}></input><button onClick={this.getTxt}>获取文本框值</button></div>);}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
12. 组件基础案例
class Hello extends React.Component {state = {txt1: "",txt2: "",list: [{id: "1",name: "jack",content: "111111",},{id: "2",name: "jack666666",content: "222222",},{id: "3",name: "jack999999965666",content: "333333",},],};btn = () => {console.log(111);};//优化renderList() {return this.state.list.length === 0 ? (<div>暂无评论</div>) : (<ul>{this.state.list.map((item) => {return (<li key={item.id}>评论人{item.name} <br></br> 内容{item.content}</li>);})}</ul>);}handleForm = (e) => {const { name, value } = e.target;this.setState({[name]: value,});};add = () => {const { list, txt1, txt2 } = this.state;// 去除首尾空格 如果空 就提示 下面代码不执行if (txt1.trim() === "" || txt2.trim() === "") {console.log("请输入name或者content");return;}const newList = [{id: new Date().getTime(),name: txt1,content: txt2,},...list,];console.log(newList);// 更新state状态this.setState({list: newList,});// 清空文本框this.setState({txt1: "",txt2: "",});};render() {const { txt1, txt2 } = this.state;return (<div><inputtype="text"onChange={this.handleForm}value={txt1}placeholder="请输入评论人"name="txt1"></input><textareaonChange={this.handleForm}value={txt2}name="txt2"></textarea><button onClick={this.add}>发表评论</button>{/* 没优化版本 */}{/* 如果list没有数据 就是暂无评论 否则 就循环渲染 */}{/* {this.state.list.length === 0 ? (<div>暂无评论</div>) : (<ul>{this.state.list.map(item => {return <li key={item.id}>评论人{item.name} <br></br> 内容{item.content}</li>})}</ul>)} */}{/* 优化版本 */}{this.renderList()}</div>);}
}ReactDOM.render(<Hello></Hello>, document.getElementById("root"));
13. 组件通讯
props
// 2 props 接收
const Hello = (props) => {console.log(props);return (<div><span>{props.name} {props.age}</span></div>);
};// 1 传递
ReactDOM.render(<Hello name="jsck" age={22}></Hello>,document.getElementById("root")
);
// 2 props 接收
class Hello extends React.Component {render() {console.log(this.props);return (<div>{this.props.name}{this.props.age}</div>);}
}// // 1 传递
ReactDOM.render(<Hello name="jsck" age={22}></Hello>,document.getElementById("root")
);
// 推荐使用 props作为consttuctor参数
// 2 props 接收
class Hello extends React.Component {constructor(props) {super(props);console.log(props);}render() {console.log(this.props);return (<div>{this.props.name}{this.props.age}</div>);}
}// 1 传递
ReactDOM.render(<Hello name="jsck" age={22}></Hello>,document.getElementById("root")
);
父传子
// 父传子
// 父组件
class Parent extends React.Component {state = {name: "wang1",};render() {return (<div>我是父组件<Child name={this.state.name}></Child></div>);}
}// 子组件
const Child = (props) => {return (<div><p>我是子组件 接收父组件数据为:{props.name}</p></div>);
};ReactDOM.render(<Parent name="jsck" age={22}></Parent>,document.getElementById("root")
);
子传父
// 父组件
class Parent extends React.Component {state = {parentMsg: "",};getChildMsg = (data) => {console.log("接收子组件数据wei:" + data);this.setState({parentMsg: data,});};render() {return (<div>父组件 aaa {this.state.parentMsg}<hr></hr>子组件:<Child getMsg={this.getChildMsg}></Child></div>);}
}class Child extends React.Component {state = {msg: "子组件数据 ",};handClick = () => {this.props.getMsg(this.state.msg);};render() {return (<div>我是子组件<button onClick={this.handClick}>点我给父组件传递数据</button></div>);}
}ReactDOM.render(<Parent name="jsck" age={22}></Parent>,document.getElementById("root")
);
兄弟相传
//思路: 将共享状态提升到最近的公共父组件中 由公共父组件管理这个状态//子组件通过props接收
class Parent extends React.Component {// 提供共享状态state = {num: 0}// 提供修改状态方法changeNum = () => {this.setState({num: this.state.num + 1})}render() {return (<div><Child1 num={this.state.num}></Child1><Child2 changeNum={this.changeNum}></Child2></div>)}
}const Child1 = (props) => {return <h1>计数器:{props.num}</h1>
}const Child2 = (props) => {return <button onClick={props.changeNum}>+1</button>
}ReactDOM.render(<Parent name="jsck" age={22}></Parent>, document.getElementById('root'))
拆分组件式
index.js :
import Child1 from "./components/Child1";
import Child2 from "./components/Child2";class Parent extends React.Component {// 提供共享状态state = {num: 0}// 提供修改状态方法changeNum = () => {this.setState({num: this.state.num + 1})}render() {return (<div><Child1 num={this.state.num}></Child1><Child2 changeNum={this.changeNum}></Child2></div>)}
}ReactDOM.render(<Parent></Parent>, document.getElementById('root'))
Child1.js :
import React from "react";class Child1 extends React.Component {constructor(props) {super(props);console.log(props);}render() {return (<div>计数器:{this.props.num}</div>)}
}export default Child1
Child2.js :
import React from "react";class Child2 extends React.Component {constructor(props) {super(props);console.log(props);}render() {return (<button onClick={this.props.changeNum}>+1</button>)}
}export default Child2
14 Context 跨组件传递数据
类似于vue的 vuex
步骤
// 组件 app node subNode Child 从app组件传到Child组件
// 用props 一层一层传 繁琐用React.createContext() 简便
1. 调用 React.createContext() 创建 Provider(提供数据) 和 Consumer(消费数据) 两个组件2. 使用Provider组件作为父节点<Provide><div className="App"><Child1></Child1></div></Provide>3. 设置value属性 表示要传递的值<Provider value="pink"></Provider>4. 调用Consumer组件接收数据<Consumer Consumer >通过回调函数的参数拿到传递过来的value的值{data => <span >data参数表示接收到的数据----{data}</span >}</Consumer
代码
const { Provider, Consumer } = React.createContext()
class App extends React.Component {render() {// 用Provide包裹内容return (<Provider value="pink"><div className="App"><Node></Node></div></Provider>)}
}const Node = props => {return (<div><SubNode></SubNode></div>)
}
const SubNode = props => {return (<div><Child1></Child1></div>)
}
const Child1 = props => {return (<div><div> 我是Child1组件</div><Consumer>{data => <span>我是接收过来的值---{data}</span>}</Consumer></div>)
}
ReactDOM.render(<App></App>, document.getElementById('root'))
15. props深入
children属性 props.children
const Parent = props => {console.log(props)// 输出为 : children : "我是子组件子节点"props.children()return (<div>{props.children}</div>)
}// const Text = () => {
// return <h1>我是组件</h1>
// }//<Parent></Parent>里面可以是文字 标签 组件 react元素 等
// ReactDOM.render(<Parent>我是子组件子节点</Parent>, document.getElementById('root'))
// ReactDOM.render(<Parent><h1>h1标签</h1></Parent>, document.getElementById('root'))
// ReactDOM.render(<Parent><Text></Text></Parent>, document.getElementById('root'))
ReactDOM.render(<Parent>{() => console.log('这是一个函数子节点')}</Parent>, document.getElementById('root'))
props校验 约束规则 默认值
//校验
// 允许在创建组件的时候 指定props的类型 格式等
// 安装包 yarn add prop-types npm i props-types
// 导入包 import PropTypes from "prop-types";
// 使用组件名.propTypes{}
// 检验规则通过PropTypes对象来指定import PropTypes from "prop-types";const App = props => {const arr = props.colorsconst lis = arr.map((item, index) => <li key={index}>{item.name}</li>)return <ul>{lis}</ul>
}App.propTypes = {colors: PropTypes.array
}ReactDOM.render(<App colors={[{ name: "123" }]}></App>, document.getElementById('root'))// 约束规则
//常见类型 array bool func number object string
//React元素 element
//必填项 isRequired
//特定结构的对象 .shape({})import PropTypes from "prop-types";const App = props => {return (<div><h1>props检验</h1></div>)
}App.propTypes = {num: PropTypes.number,//数字fn: PropTypes.func.isRequired, // 函数 isRequired必填项tag: PropTypes.element, //react元素filter: PropTypes.shape({ //filter类型 对象({})area: PropTypes.string,price: PropTypes.number})
}ReactDOM.render(<App fn={() => { }}></App>, document.getElementById('root'))// props 默认值 未传入时生效// 场景 分页组件const App = props => {console.log(props)return (<div>prpos默认值</div>)
}// 以传入的值为主
App.defaultProps = {pagSize: 10
}// pagSize 10
ReactDOM.render(<App></App>, document.getElementById('root'))// pagSize 20
ReactDOM.render(<App pagSize={20}></App>, document.getElementById('root'))
16. 生命周期
创建 | ||
钩子函数 | 触发时机 | 作用 |
constructor | 创建组件时 | 1.初始化state 2.为事件处理绑定this |
render | 每次组件渲染时都会触发 | 渲染UI 注意不能调用setState() |
componentDidMount | 组件挂载后(完成DOM渲染) | 1.发送网络请求 2.DOM操作 |
更新 | ||
钩子函数 | 触发时机 | 作用 |
render | 每次组件渲染都会触发 | 渲染UI 挂载阶段是同一个render |
componentDidUpdate | 组件更新后 | 1. 发送网络请求 1. DOM操作 注意 如果要setState() 必须放在一个 if 条件中 |
卸载 | ||
钩子函数 | 触发时机 | 作用 |
componentWillUnmount | 组件卸载(从页面中消失) | 执行清理工作 (清除定时器) |
创建 | ||
钩子函数 | 触发时机 | 作用 |
constructor | 创建组件时 | 1.初始化state 2.为事件处理绑定this |
render | 每次组件渲染时都会触发 | 渲染UI 注意不能调用setState() |
componentDidMount | 组件挂载后(完成DOM渲染) | 1.发送网络请求 2.DOM操作 |
// 创建时
// 执行顺序 constructor() => render() => componentDidMountclass App extends React.Component {constructor(props) {super(props)// 初始化statethis.state = {num: 0}console.log('1生命周期函数---constructor')}componentDidMount() {// 获取DOM操作// console.log(document.getElementById('header'))// 发送ajax请求 axios.get("")console.log('2生命周期函数---componentDidMount')}render() {// 错误演示 不要再render中调用setState()// this.setState({// num: 1// })console.log('3生命周期函数---render')return (<div><h1 id="header">header</h1></div>)}
}ReactDOM.render(<App ></App>, document.getElementById('root'))
```js
//更新时
//执行时机 1.setState() 2. forceUpdate() 3. 组件接收的props//执行顺序 render() => componentDidUpdate()
更新 | ||
钩子函数 | 触发时机 | 作用 |
render | 每次组件渲染都会触发 | 渲染UI 挂载阶段是同一个render |
componentDidUpdate | 组件更新后 | 1. 发送网络请求 1. DOM操作 注意 如果要setState() 必须放在一个 if 条件中 |
class App extends React.Component {
constructor(props) {
console.log(‘constructor’)
super(props)
this.state = {
num: 0
}
}
handerNum = () => {
this.setState({
num: this.state.num + 1
})
// 演示强制更新
// this.forceUpdate()
}
render() {
console.log(‘render’)
return (
+1
)
}
}
class Numb extends React.Component {
render() {
console.log(‘子组件------render’)
return (
统计次数:{this.props.num}
)
}
// 如果调用setState 必须放在if中
componentDidUpdate(prevProps) {
console.log(‘子组件生命周期 componentDidUpdate’)
// 获取DOM
console.log(document.getElementById(‘title’))
// this.setState({}) 报错 会递归更新
console.log('上次props', prevProps)console.log('当前props', this.props)// // 正确写法 比较更新前后的props是否相同 来决定重新渲染条件// if (prevProps.num !== this.props.num) {// this.setState({})// // 发送ajax// }
}
}
ReactDOM.render(, document.getElementById(‘root’))
```
卸载 | ||
钩子函数 | 触发时机 | 作用 |
componentWillUnmount | 组件卸载(从页面中消失) | 执行清理工作 (清除定时器) |
// 卸载时
// 执行时机 组件从页面中消失class App extends React.Component {constructor(props) {console.log('constructor')super(props)this.state = {num: 0}}handerNum = () => {this.setState({num: this.state.num + 1})// 演示强制更新// this.forceUpdate()}render() {console.log('render')return (<div>{this.state.num > 3 ? <p>豆豆打死了</p> : <Numb num={this.state.num}></Numb>}<button onClick={this.handerNum}>+1</button></div>)}
}class Numb extends React.Component {render() {console.log('子组件------render')return (<div><h1 id="title">统计次数:{this.props.num}</h1></div>)}componentDidMount() {// 开启定时器this.inter = setInterval(() => {console.log('定时器正在执行')}, 500);}componentWillUnmount() {console.log('生命周期 componentWillUnmount')// 清除定时器clearInterval(this.inter)}}ReactDOM.render(<App ></App>, document.getElementById('root'))
17. render props 和 高阶组件
react组件复用
复用相似功能
复用什么? 1. state 2. 操作state的方法
两种方式 1. render props模式 2.高阶组件(HOC)
思路:将要复用的state和操作state的方法封装到一个组件中
// 创建Mouse组件
// class Mouse extends React.Component {
// state = {
// x: 0,
// y: 0
// }// // 鼠标移动事件
// handleMouseMove = e => {
// this.setState({
// x: e.clientX,
// y: e.clientY,
// })
// }
// // 监听鼠标移动事件
// componentDidMount() {
// window.addEventListener('mousemove', this.handleMouseMove)
// }// render() {
// // return null;
// // console.log(this.props.render)
// return this.props.renderss(this.state)
// }
// }// class App extends React.Component {
// render() {
// return (
// <div>
// 111
// <Mouse renderss={(mouse) => {
// return <p>鼠标位置:x{mouse.x},y:{mouse.y}</p>
// }}></Mouse>// <Mouse renderss={mouse => {
// return <p style={{ position: 'absolute', top: mouse.y, left: mouse.x }}>看我!!!</p>
// }}></Mouse>
// </div>
// )
// }
// }// ReactDOM.render(<App ></App>, document.getElementById('root'))
render props模式 children代替render属性
// render props模式 childern代替render属性
class Mouse extends React.Component {state = {x: 0,y: 0}// 鼠标移动事件handleMouseMove = e => {this.setState({x: e.clientX,y: e.clientY,})}// 监听鼠标移动事件componentDidMount() {window.addEventListener('mousemove', this.handleMouseMove)}render() {// return null;// console.log(this.props.render)return this.props.children(this.state)}
}class App extends React.Component {render() {return (<div>111<Mouse>{mouse => {return <p>鼠标位置:x{mouse.x},y:{mouse.y}</p>}}</Mouse><Mouse>{mouse => {return <p style={{ position: 'absolute', top: mouse.y, left: mouse.x }}>看我!!!</p>}}</Mouse></div>)}
}ReactDOM.render(<App ></App>, document.getElementById('root'))
render props 代码优化 添加props校验
import PropTypes from 'prop-types'
class Mouse extends React.Component {state = {x: 0,y: 0}handleMove = (e) => {this.setState({x: e.clientX,y: e.clientY})}componentDidMount() {window.addEventListener("mousemove", this.handleMove)}// 删除监听// 在组建卸载时移除事件绑定componentWillUnmount() {window.removeEventListener("mousemove", this.handleMove())}render() {return this.props.children(this.state)}
}// 添加props校验
Mouse.propTypes = {children: PropTypes.func.isRequired
}class App extends React.Component {render() {return (<div>1111<Mouse>{mouse => {return <p>鼠标位置:x{mouse.x},y:{mouse.y}</p>}}</Mouse><Mouse>{mouse => {return <p style={{ position: 'absolute', top: mouse.y, left: mouse.x }}>看我!!!</p>}}</Mouse></div>)}
}ReactDOM.render(<App ></App>, document.getElementById('root'))
高阶组件
使用步骤
1.创建一个函数 名称以with开头
2.指定函数参数 参数以大写字母开头 (作为要渲染的组件)
3.在函数内部创建一个类组件,提供复用的状态逻辑代码 并返回
4.在该组件中 渲染参数组件 同时将状态通过prop传递给参数组件
\5. 调用该高阶组件 传入要增强的组件 通过返回值拿到增强后的组件 渲染页面
function withMouse (WrapperComponent){
class Mouse extends React.Component{}
return Mouse
}
Mouse组件的render方法中
return <WrapperComponent {…this.state}>
// // 创建高阶组件
// function withMouse(WrappenComponent) {
// // 该组件提供付永德状态逻辑
// class Mouse extends React.Component {
// // 鼠标状态
// state = {
// x: 0,
// y: 0
// }
// handleMove = e => {
// this.setState({
// x: e.clientX,
// y: e.clientY
// })
// }// // 控制鼠标状态的逻辑
// componentDidMount() {
// window.addEventListener("mousemove", this.handleMove)
// }// componentWillUnmount() {
// window.removeEventListener("mousemove", this.handleMove)
// }// render() {
// return <WrappenComponent {...this.state}></WrappenComponent>
// }// }// return Mouse// }// const Position = props => {// return <p>
// 鼠标位置:x{props.x} y: {props.y}
// </p>
// }// const ThisPosition = (props) => {
// return <p style={{ position: 'absolute', top: props.y, left: props.x }}>看我!!!</p>
// }// // 获取增强后的组件
// const MousePosition = withMouse(Position)
// const ThisMousePosition = withMouse(ThisPosition)// class App extends React.Component {
// render() {
// return (
// <div>
// 高阶组件// {/* 渲染增强后逇组件 */}// <MousePosition></MousePosition>
// <ThisMousePosition />
// </div>
// )
// }
// }// ReactDOM.render(<App />, document.getElementById('root'))
displayName属性
// 设置displayName
// 不设置 React调试器 都显示Mouse
// 便于调试区分// 创建高阶组件
// function withMouse(WrappenComponent) {
// // 该组件提供付永德状态逻辑
// class Mouse extends React.Component {
// // 鼠标状态
// state = {
// x: 0,
// y: 0
// }
// handleMove = e => {
// this.setState({
// x: e.clientX,
// y: e.clientY
// })
// }// // 控制鼠标状态的逻辑
// componentDidMount() {
// window.addEventListener("mousemove", this.handleMove)
// }// componentWillUnmount() {
// window.removeEventListener("mousemove", this.handleMove)
// }// render() {
// return <WrappenComponent {...this.state}></WrappenComponent>
// }// }// // // 设置displayName
// Mouse.displayName = `WithMouse${getDisplayName(WrappenComponent)}`// function getDisplayName(WrappenComponent) {
// return WrappenComponent.displayName || WrappenComponent.name || 'Component'
// }// return Mouse// }// const Position = props => {// return <p>
// 鼠标位置:x{props.x} y: {props.y}
// </p>
// }// const ThisPosition = (props) => {
// return <p style={{ position: 'absolute', top: props.y, left: props.x }}>看我!!!</p>
// }// // 获取增强后的组件
// const MousePosition = withMouse(Position)
// const ThisMousePosition = withMouse(ThisPosition)// class App extends React.Component {
// render() {
// return (
// <div>
// 高阶组件// {/* 渲染增强后逇组件 */}// <MousePosition></MousePosition>
// <ThisMousePosition />
// </div>
// )
// }
// }// ReactDOM.render(<App />, document.getElementById('root'))
高阶组件传递props
// 问题 props丢失
// 原因 高阶组件没有往下传递props
// 解决方法 渲染WrappedComponen时 讲state和this.props一起传递给组件function withMouse(WrappenComponent) {// 该组件提供付永德状态逻辑class Mouse extends React.Component {// 鼠标状态state = {x: 0,y: 0}handleMove = e => {this.setState({x: e.clientX,y: e.clientY})}// 控制鼠标状态的逻辑componentDidMount() {window.addEventListener("mousemove", this.handleMove)}componentWillUnmount() {window.removeEventListener("mousemove", this.handleMove)}render() {console.log(this.props, 'Mouse组件')// return <WrappenComponent {...this.state}></WrappenComponent>return <WrappenComponent {...this.state} {...this.props}></WrappenComponent>}}// // 设置displayNameMouse.displayName = `WithMouse${getDisplayName(WrappenComponent)}`function getDisplayName(WrappenComponent) {return WrappenComponent.displayName || WrappenComponent.name || 'Component'}return Mouse}const Position = props => {console.log(props, 'Position组件')// 拿不到传过来的a// 问题 props丢失// 原因 高阶组件没有往下传递props// 解决方法 渲染WrappedComponen时 将state和this.props一起传递给组件// return <WrappenComponent {...this.state} {...this.props}></WrappenComponent>return <p>鼠标位置:x{props.x} y: {props.y}</p>
}// 获取增强后的组件
const MousePosition = withMouse(Position)class App extends React.Component {render() {return (<div>高阶组件{/* 渲染增强后逇组件 */}<MousePosition a="1"></MousePosition></div>)}
}ReactDOM.render(<App />, document.getElementById('root'))
18. react原理揭秘
setState的说明
// setState的说明
// setstate更新数据是异步的// 推荐使用setState((state,props)=>{}) 参数state:表示最新的state props表示最新的propsclass App extends React.Component {state = {num: 0}handleClick = () => {// 更新state 是异步的// this.setState({// num: this.state.num + 1// })// console.log(this.state.num) //0// this.setState({// num: this.state.num + 1// })// 后面的setState不要依赖于前面的setState// this.setState调用两次 render只调用一次// 推荐语法: 也是异步的// 调用一次 参数state还是原来的statethis.setState((state, props) => {return {num: state.num + 1}})console.log(this.state.num) //0// 调用第二次 这次的state参数 是上次调用之后的statethis.setState((state, props) => {return {num: state.num + 1}})console.log(this.state.num)//2}render() {console.log('render')return (<div>计数器 {this.state.num}<button onClick={this.handleClick}>+1</button></div>)}
}ReactDOM.render(<App />, document.getElementById('root'))
setState 第二个参数
// setState第二个参数 propsclass App extends React.Component {state = {num: 0}handleClick = () => {this.setState((state, props) => {return {num: state.num + 1}}, () => { //状态更新后并且更新渲染后,立即执行 可以操作DOMconsole.log('状态更新', this.state.num) //1console.log(document.getElementById('title'))document.title = '更新标题'})console.log(this.state.num) //0}render() {console.log('render')return (<div>计数器 {this.state.num}<h1 id="title">111111111111</h1><button onClick={this.handleClick}>+1</button></div>)}
}ReactDOM.render(<App />, document.getElementById('root'))
19. JSX 语法转化过程
// // jsx是createElement的语法糖 jsx被@bable/preset-react编译为createElement// // jsx
// // const element = <h1 className="eleme">helo jsx</h1>
// // console.log(element)// // createElement
// const element = React.createElement(
// 'h1',
// {
// className: "elem"
// },
// "hello jsx"
// )// console.log(element)// ReactDOM.render(element, document.getElementById('root'))
2. 组件性能优化
// 1) 减轻state
// 只存储跟组件渲染相关的数据 比如列表数据 loading等
// 注意 不用做渲染的数据不要放在state中 比如定时器 直接放在this当中 直接this.setinter=setInterval(() => { }, 500);// 2)避免不必要的重新渲染
// 组件更新机制 父组件更新 会引起子组件也会更新
// 问题 子组件没有任何变化时也会重新渲染
// 解决方法:使用钩子函数 shouldComponentUpdate(nextProps,nextState)
// 作用 通过返回值决定该组件是否重新渲染 返回true表示重新渲染 false表示不能
// 触发时机 更新阶段的钩子函数 组件重新渲染 前 执行 (shouldComponentUpdate => render)
// class App extends React.Component {// // true 渲染页面 false 不渲染
// shouldComponentUpdate(nextProps, nextState) {
// console.log(nextProps) //最新的props
// console.log(nextState) //最新的state
// console.log(this.state) // 更新前的状态
// return true
// }
// state = {
// num: 0
// }// handleClick = () => {
// this.setState((state) => {
// return {
// num: state.num + 1
// }
// })
// }// render() {
// return (<div>{this.state.num}// <button onClick={this.handleClick}>+1</button>
// </div>)
// }
// }// ReactDOM.render(<App />, document.getElementById('root'))
案例
// 案例
class App extends React.Component {state = {num: 0}handleClick = () => {this.setState((state) => {return {num: Math.floor(Math.random() * 3) // 0-3 随机数}})}// 因为两次生成的随机数相同 就不必要重新渲染shouldComponentUpdate(nextProps, nextState) {// if (nextState.num === this.state.num) {// return false// } else {// return true// }return nextState.num !== this.state.num}render() {console.log('render')return (<div>{this.state.num}<button onClick={this.handleClick}>随机数</button></div>)}
}ReactDOM.render(<App />, document.getElementById('root'))
通过props避免不必要的重新渲染
//利用props 避免不必要的重新渲染class App extends React.Component {state = {num: 0}handleClick = () => {this.setState((state) => {return {num: Math.floor(Math.random() * 3) // 0-3 随机数}})}render() {return (<div><NumberBox number={this.state.num}></NumberBox><button onClick={this.handleClick}>随机数</button></div>)}
}class NumberBox extends React.Component {shouldComponentUpdate(nextProps) {console.log(nextProps)console.log(this.props)return nextProps.number !== this.props.number}render() {console.log('render')return (<div>随机数{this.props.number}</div>)}
}ReactDOM.render(<App />, document.getElementById('root'))
纯组件 (内部自动实现shouldComponentUpdate)
// 纯组件
// 纯组件 PureComponent 与React.Component功能相似
// 区别 PureComponent内部自动实现了 shouldComponentUpdate 不需要手动比较
// 原理 纯组件内部通过分别对比前后两次props和state的值 来决定是否重新渲染组件// import { PureComponent } from "react";
// class App extends PureComponent { // 可以写为class App extends React.PureComponent { 就不需要引入
// state = {
// num: 0
// }// handleClick = () => {
// this.setState((state, props) => {
// return {
// num: Math.floor(Math.random() * 3)
// }
// })
// }// render() {
// console.log('render')
// return (
// <div>
// 随机数 {this.state.num}
// <button onClick={this.handleClick}>随机</button>
// </div>
// )
// }
// }// ReactDOM.render(<App />, document.getElementById('root'))
import { PureComponent } from "react";class App extends React.Component {state = {num: 0}handleClick = () => {this.setState((state, props) => {return {num: Math.floor(Math.random() * 3)}})}render() {return (<div><NumberBox number={this.state.num}></NumberBox><button onClick={this.handleClick}>随机</button></div>)}
}class NumberBox extends PureComponent {render() {console.log('render')return <div>suijiahsu1 {this.props.number}</div>}
}ReactDOM.render(<App />, document.getElementById('root'))
21 好客租房 项目
### 1. 项目搭建
npx create-react-app hkzf
yarn start
2. 组件库 antd-mobile
1 打开文档 http://ant-design-mobile.antgroup.com/zh/components/button
3. 配置基础路由
yarn add react-router-dom
import { BrowserRouter as Router, Route, Routes, Link } from ‘react-router-dom’
4. 外观和样式调整
index.css
html,
body {height: 100%;font-family: "Microsoft YaHei";color: #333;background-color: #fff;
}
* {box-sizing: border-box;
}
5. 两种布局页面
- 有tabber页面
- 无tabbar页面
6. 嵌套路由
v6版本
render() {return <div className="home">shouye<Button size='large' color='primary'>xxxxxxxxxxxxx</Button>{/* <Route path="/news" element={<News />}></Route> */}<Link to="/home/news">news</Link><Routes>{/* <Route path="/*" ></Route> */}<Route path="/" element={<News />}></Route><Route path="/a" element={<A />}></Route></Routes></div>}
v6之前版本:
render() {return (<div style={{ background: "red", padding: "10px" }} className="home">shouye<Button size='large' color='primary'>xxxxxxxxxxxxx</Button><Route path="/home/news" component={News}></Route></div>)}
}
附加
1.关闭 eslint
package.json 中修改
"eslintConfig": {"extends": ["react-app","react-app/jest"],"rules": {"no-undef": "off","no-restricted-globals": "off","no-unused-vars": "off"}},
相关文章:
react学习笔记,ReactDOM,react-router-dom
react 学习 1. 下载与安装 下载 npm install -g create-react-app 安装 npx create-react-app xxx 推荐 npm init react-app xxx yarn create react-app xxx 2. 创建 react 元素 indexjs 文件 import React from "react"; import ReactDOM from "react…...

优化UVM环境(八)-整理project_common_pkg文件
书接上回: 优化UVM环境(七)-整理环境,把scoreboard拿出来放在project_common环境里 Prj_cmn_pkg.sv考虑到是后续所有文件的基础,需要引入uvm_pkg并把自身这个pkg import给后续的文件: 这里有3个注意事项&…...

【实战案例】Django框架连接并操作数据库MySQL相关API
本文相关操作基于上次操作基本请求及响应基础之上【实战案例】Django框架基础之上编写第一个Django应用之基本请求和响应 Django框架中默认会连接SQLite数据库,好处是方便无需远程连接,打包项目挪到其他环境安装一下依赖一会就跑起来,但是缺点…...

【其他】无法启动phptudy服务,提示错误2:系统找不到指定的文件
在服务中启动phpstudy服务时,提示“windows 无法启动phpstudy服务 服务(位于本地计算机上) 错误2:系统找不到指定的文件”的错误。导致错误的原因是可执行文件的路径不对,修改成正确的路径就可以了。 下面是错误的路径,会弹出错误窗口&#…...

AI驱动的支持截图或线框图快速生成网页应用的开源项目
Napkins.dev是什么 Napkins.dev是一个创新的开源项目,基于AI技术将用户的截图或线框图快速转换成可运行的网页应用程序。项目背后依托于Meta的Llama 3.1 405B大型语言模型和Llama 3.2 Vision视觉模型,结合Together.ai的推理服务,实现从视觉设…...

es集群索引是黄色
排查 GET /_cat/shards?hindex,shard,prirep,state,unassigned.reason 查询原因 发现node正常 执行重新分配 retry_failedtrue 参数告诉Elasticsearch重试那些因某种原因(如节点故障、资源不足等)而失败的分片分配。这个选项通常用来尝试再次分配那些…...

获取淘宝商品评论的方法分享-调用API接口item_review
在电商领域,商品评论是消费者了解产品、做出购买决策的重要依据。淘宝作为中国最大的电商平台之一,其商品评论系统涵盖了海量的用户反馈数据。为了帮助企业、电商数据分析师、市场研究人员以及普通消费者更高效地获取这些评论数据,淘宝开放平…...

MATLAB人脸考勤系统
MATLAB人脸考勤系统课题介绍 该课题为基于MATLAB平台的人脸识别系统。传统的人脸识别都是直接人头的比对,现实意义不大,没有一定的新意。该课题识别原理为:先采集待识别人员的人脸,进行训练,得到人脸特征值。测试的时…...

Spring篇(事务篇 - 基础介绍)
目录 一、JdbcTemplate(持久化技术) 1. 简介 2. 准备工作 2.1. 引入依赖坐标 2.2. 创建jdbc.properties 2.3. 配置Spring的配置文件 3. 测试 3.1. 在测试类装配 JdbcTemplate 3.2. 测试增删改功能 查询一条数据为实体类对象 查询多条数据为一个…...

qt EventFilter用途详解
一、概述 EventFilter是QObject类的一个事件过滤器,当使用installEventFilter方法为某个对象安装事件过滤器时,该对象的eventFilter函数就会被调用。通过重写eventFilter方法,开发者可以在事件处理过程中进行拦截和处理,实现对事…...

[ 钓鱼实战系列-基础篇-6 ] 一篇文章让你了解邮件服务器机制(SMTP/POP/IMAP)-1
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...
wordpress伪静态规则
WordPress 伪静态规则是指将 WordPress 生成的动态 URL 转换为静态 URL 的规则,这样做可以提高网站的搜索引擎优化(SEO)效果,并且使得 URL 更加美观、易于记忆。伪静态规则通常需要在服务器的配置文件中设置,不同的服务器环境配置方法有所不同…...

缓存框架JetCache源码解析-缓存定时刷新
作为一个缓存框架,JetCache支持多级缓存,也就是本地缓存和远程缓存,但是不管是使用着两者中的哪一个或者两者都进行使用,缓存的实时性一直都是我们需要考虑的问题,通常我们为了尽可能地保证缓存的实时性,都…...

docker配置mysql8报错 ERROR 2002 (HY000)
通过docker启动的mysql,发现navicat无法连接,后来进入容器内部也是无法连接,产生以下错误 root9f3b90339a14:/var/run/mysqld# mysql -u root -p Enter password: ERROR 2002 (HY000): Cant connect to local MySQL server through socket …...

【Linux】为什么环境变量具有全局性?共享?写时拷贝优化?
环境变量表具有全局性的原因: 环境变量表之所以具有全局性的特征,主要是因为它们是在进程上下文中维护的,并且在大多数操作系统中,当一个进程创建另一个进程(即父进程创建子进程)时,子进程会继承…...
如何在Linux中找到MySQL的安装目录
前言 发布时间:2024-10-22 在日常管理和维护数据库的过程中,了解MySQL的确切安装位置对于执行配置更改、更新或者进行故障排查是非常重要的。本文将向您介绍几种在Linux环境下定位MySQL安装路径的方法。 通过命令行工具快速定位 使用 which 命令 首…...
机器人备件用在哪些领域
机器人备件,作为机器人技术的重要组成部分,被广泛应用于多个领域,以提高生产效率、降低成本、增强产品质量,并推动相关行业的智能化发展。以下是一些主要的应用领域: 制造业: 机器人备件在制造业中的应用最…...
基于单片机优先级的信号状态机设计
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、背景知识二、使用步骤1.定义相应状态和信号列表2.获取最高优先级信号3.通用状态机实现4.灯的控制函数 总结 前言 在嵌入式系统中,设备控制的灵…...
数字电路week3
数字电路学习 九.补充 1.Verilog和fpga verilog是一种描述电路的语言,出现于上世纪80年代 非:~与: &,或: |,异或: ^ fpga:一种可编程逻辑器件 FPGA 由大量的逻辑单元、查找表(LUTs)、触发…...

如何在 Linux 中对 USB 驱动器进行分区
如何在 Linux 中对 USB 驱动器进行分区 一、说明 为了在 Linux 上访问 USB 驱动器,它需要有一个或多个分区。由于 USB 驱动器通常相对较小,仅用于临时存储或轻松传输文件,因此绝大多数用户会选择只配置一个跨越整个 USB 磁盘的分区。但是&a…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...