react优势
-
React主要用于构建UI,通过对DOM的模拟,最大限度地减少与DOM的交互;
-
组件构建,代码复用
-
单向的响应数据流,state通过与用户交互来改变状态,props是不变的,通常将父组件设置为state,子组件设置为props;
-
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
react和react-dom库的作用
react 构建的是虚拟dom react-dom 的作用是将虚拟dom转换成真实dom
react知识点
class组件特性
- 组件首字母必须大写
- 组件必须继承自 React.Component
- 组件必须有一个 render 方法
- render 方法的返回值,是该组件要输出的视图
什么是jsx
const element = <h1>Hello, world!</h1>;
它既不是html也不是字符串,这种语法称为jsx。JSX最终会被编译为合法的JS语句调用(编译器在遇到{时采用JS语法进行解析,遇到<就采用HTML规则进行解析)
元素渲染
元素(elements)是构成React应用的最小单元,元素描述了想要在屏幕中看到的内容,如:
const element = <h1>Hello, world</h1>;
和DOM元素不同的是,React元素是纯对象,创建的代价低。并且React会进行优化处理,只把有必要的变化更新到DOM上。此外,元素和组件的概念,是不一样的,组件是由元素组成的。
在React中,使用ReactDOM.render()方法来将React元素渲染进一个DOM中。如:
ReactDOM.render(
element,
document.getElementById('root')
)
在实际开发中,大多数React应用只会调用一次ReactDOM.render(),所以更好的方式是使用有状态组件
组件
组件(component)能够将UI划分为独立的、可复用的部分,这样我们就只需专注于构建每一个单独的部件。 从概念上看,组件就像是函数:接受任意的输入(称为属性,Props),返回React元素。React中有两种定义组件的方式:函数定义和类定义。
- 函数定义组件 这种方式是最简单的定义组件的方式,就像写一个JS函数一样,如:
function Welcome (props) {
return <h1>Hello, {props.name}</h1>;
}
- 类定义组件 使用es6中的类来定义一个组件
class Welcome extends React.Component {
render () {
return <h1>Hello, {this.props.name}<h1>;
}
}
这种方式可以做更多的事情,如:生命周期
注意: 在React中,组件必须返回单一的根元素,这也是为什么App组件中需要用
state
state 用于组件内部的数据传递,state 是私有的,可以认为 state 是组件的私有属性。
构建函数 constructor 是唯一可以初始化 state 的地方。
setState 特性
- 1、不可变值 意思是,不能直接给 state 赋值,需要使用 setState 去操作。 如果 state 为数组或对象,操作时不能影响到原数组或原对象。
- 2、setState 默认异步更新
- 3、setState 默认会合并后更新
- 4、setState 同步更新 ——— 一切不在 react 上下文中触发的都是同步更新
- setTimeout、setInterval、promise.then
setTimeout(() => {
this.setState({
num: 2
})
console.log('num: ', this.state.num); // num: 2
}, 1000);
* 自定义的 DOM 事件
* ajax 回调
* setState 的第二个参数是回调函数,里面打印的也是同步更新
```js
this.setState({
count: this.state.count + 1
}, () => {
console.log(this.state.count);
console.log('加载完成')
});
```
* react 18 中,上述场景也可以为异步更新,需要将 ReactDOM.render 替换为 ReactDOM.createRoot
- 5、setSate 不合并的情况
- state 同步更新
- setState 传入函数时
this.setState((prevState, props) => { return { val: prevState + 1 } }) - 6、flushSync 方法可以强制 setState 同步
props
本质上,props就是传入函数的参数,是从传入组件内部的数据。更准确的说,是从父组件传递向子组件的数据。
react生命周期
初始化组件
- constructor 构造函数 生命周期开始。 初始化state、为事件处理函数绑定实例要在这个生命周期进行。super(props)也要放在这个生命周期,不然拿不到 this.props。
- render 渲染 组件已经渲染出来了
- componentDidMount 组件加载完成 组件已经挂载成功了,可以在这个生命周期做定时器等操作
更新组件
- shouldComponentUpdate 子组件是不是应该更新 此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。应该考虑使用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()
- render 渲染
- componentDidUpdate 组件更新完成 当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求
销毁组件
- componentWillUnmount 组件将要销毁
input输入(借用事件)
这里有两个知识点: 1、在输入时,需要动态修改值 2、调用事件时, this 的指向问题
constructor(props) {
super(props)
this.state = {
inputValue: ""
}
// 解决 this 指向
// 方式一, 在构造函数中加
his.inputChange = this.inputChange.bind(this)
}
// 方式二: 在jsx调用方法时加,但是这种方式并不推荐
// 这样写的话,每执行一次方法就要去绑定一次this
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
inputChange(e) {
this.setState({
inputValue: e.target.value
})
}
// 方式三:在方法中使用箭头函数 推荐写法
inputChange = (e) => {
this.setState({
inputValue: e.target.value
})
}
class样式
在react中使用className代替
使用style
<div style={{ paddingLeft: "40px" }}></div>
循环遍历
constructor(props) {
super(props);
this.state = {
msg: "hello world!",
lists: [
{key: "1", value: "a1"},
{key: "2", value: "a2"},
{key: "3", value: "a3"},
{key: "4", value: "a4"},
]
}
}
render() {
return (
<div>
<ul>
{
this.state.lists.map(item => {
return <li key={item.key}>{item.value}</li>
})
}
</ul>
</div>
)
}
获取父组件或自己的属性
获取父组件数据
需要现在从父子组件传值到子组件,然后在子组件中使用this.props获取父组件数据
获取自己的数据
需要先在constructor中声明,然后使用this.state获取
父组件向子组件传递数据
父组件
把数据放在arr中传给子组件(arr可以随便自定义)
<List arr={this.state.list} deleteMen={this.deleteMen.bind(this)}></List>
子组件
通过props取出arr的值
this.props.arr.map((item, index) => {
return <li key={index + item}>
<span>{item}</span>
<button onClick={this.deleteMen.bind(this, index)}>删除</button>
</li>
})
子组件修改父组件数据(借用事件)
父组件把方法当做属性传到子组件,子组件去调用来修改父组件数据
父组件
<Head
addOneTodo={this._addOneTodo}
/>
子组件
const { addOneTodo } = this.props;
addOneTodo(todo);
ref
获取ref通过:React.createRef()
转发ref通过:React.forwardRef()
案例
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// 你可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
1、我们通过调用 React.createRef 创建了一个 React ref 并将其赋值给 ref 变量。
2、我们通过指定 ref 为 JSX 属性,将其向下传递给 。
3、React 传递 ref 给 forwardRef 内函数 (props, ref) => ...,作为其第二个参数。
4、我们向下转发该 ref 参数到 ,将其指定为 JSX 属性。
5、当 ref 挂载完成,ref.current 将指向 DOM 节点。