react基础学习

78 阅读6分钟

react优势

  1. React主要用于构建UI,通过对DOM的模拟,最大限度地减少与DOM的交互;

  2. 组件构建,代码复用

  3. 单向的响应数据流,state通过与用户交互来改变状态,props是不变的,通常将父组件设置为state,子组件设置为props;

  4. 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>&nbsp;&nbsp;
            <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 节点。