React(1)-基础知识

React

React是一个声明式,高效且灵活的用于构建用户界面的JavaScript库。使用React可以将一些简短、独立的代码片段组合成复杂的UI界面,这些代码片段称为“组件”。

JSX

JSX是JavaScript的语法拓展,可以生成React“元素”。React认为渲染逻辑与其他UI逻辑内在耦合,故其没有采用将标记和逻辑分离在不同文件的方式,而是将他们共同存入“组件”的松散耦合单元中。

1
2
3
4
//JSX语法
<div />
//等同于
React.createElement('div')

在JSX中可以任意使用JavaScript表达式,只需要用大括号{}括起来。

  • 使用{}嵌入元素:可嵌入变量、表达式、函数等。

    1
    const element = <h1>Hello,{formatName(user)}</h1>;
  • 使用"":将属性值指定为字符串字面量。

    1
    const element = <div tabIndex="0"></div>;
  • 使用{}:在属性值插入一个JavaScript表达式。

    1
    const element = <img src={user.avatarUrl}></img>;
  • JSX可以安全的插入用户输入的内容:React DOM渲染输入内容前,默认会进行转义。可以确保在应用中,永远不会注入并非自己明确编写的内容。所有内容渲染之前都被转换成了字符串。此方法可以有效防止XSS(跨站脚本)攻击。

  • React.createElement():创建React对象,即React元素。描述了用户希望在屏幕上看到的内容。React通过读取这些对象并使用他们来构建DOM以及保持随时更新。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const element = {
    <h1 className="greeting">
    Hello, world!
    </h1>
    };
    //等价于
    const element = React.createElement(
    'h1',
    {className: 'greeting'},
    'Hello, world!'
    );
    //创建对象的结构如下:
    const element = {
    type: 'h1',
    props: {
    className: 'greeting',
    children: 'Hello, world!'
    }
    };

注意点:

  1. 空元素必须用/结束,如<br />

  2. 根元素不能为两个,如:

    1
    2
    3
    4
    5
    6
    7
    const element = (
    <div>
    <p>Hello World!<p>
    <br/>
    </div>
    );
    //<p>和<br/>为两个根元素,故只能用<div>包起来。
  3. JSX的属性和方法命名规则都必须为小驼峰,如className

  4. if使用&&表示,&&前为条件,后为执行的JSX语句

  5. if-else使用a?b:c,a为条件,是执行b,else执行c

  6. 循环语句使用数组的map方法实现,在回调函数里处理每个子元素。为了方便的找出哪个节点有更新,其循环的子元素都必须加唯一id。

    1
    2
    3
    4
    array.map((number) => 
    <listItem key={number.toString()} //key->唯一id
    value={number} />
    )

元素渲染

元素是构成React应用的最小模块,是创建开销极小的普通对象。

每一个React元素都是一个JavaScript对象,可以在程序中保存到变量中或作为参数传递。

1
const element = <h1>Hello, world</h1>;

若要将React元素渲染到根DOM节点root,使用ReactDOM.render()。

1
2
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

React元素不可变。一旦被创建就无法更改它的子元素或属性,它代表了某个特定时刻的UI。要修改元素只能通过重新绑定新的元素渲染或通过state修改。

组件及Props

组件,类似于JavaScript函数,接受任意的入参(props),通过render方法返回用于描述页面展示内容的React元素。

两种写法:

1
2
3
4
5
6
7
8
9
10
11
方法一:函数
function Welcome(props){
return <h1>Hello,{props.name}</h1>;
}

方法二:ES6的class
class Welcome extends React.Component{
render() {
return <h1>Hello,{props.name}</h1>;
}
}

自定义组件

1
2
3
4
5
6
7
8
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);

注意:组件名称必须使用大写字母开头。

自定义组件可以在其输出(return )中引入其他组件,即组合组件。

组合组件

多层嵌套的组合组件若其中包含可复用的组件,可将组件提取出来,构建可复用的组件库。同样,若组件本身过于复杂,也可将其中的元素提取成组件,构建为可复用的组件。

注意:组件的props绝不能修改,要像纯函数一样保护props不被修改。

纯函数:函数不会更改入参,多次调用下相同的入参返回相同的结果。

1
2
3
4
5
6
7
8
9
//非纯函数
function test(a,b){
a += b;
return a+b;
}
//纯函数
function test(a,b){
return a+b;
}

函数组件转换class组件

  1. 创建同名ES6 class,继承于React.Component
  2. 添加空的render()方法。
  3. 将函数组件的函数体移入render()方法中。
  4. render()方法中的props改为this.props
  5. 删除空的函数组件。

state&生命周期

React把组件看作状态机。通过与用户的交互,实现不同的状态,渲染UI,让用户界面和数据保持一致。state与props类似,但state是私有的,完全受控于当前组件。React中,只需更新组件的state,根据新的state重新渲染用户界面。

使用构造函数初始化this.state

1
2
3
4
5
constructor(props){
//使用super函数将props传递到父类的构造函数中
super(props);
this.state = {date: new Date()};
}

render()函数中使用this.state获取state中的值。

1
2
3
4
5
6
7
render(){
return (
<div>
<h1>It is {this.state.date.toLocaleTimeString()}.</h1>
</div>
)
}

生命周期

当组件第一次被渲染到DOM中时,调用componentDidMount()函数=> 挂载(mount)
当组件被删除时,调用componentWillUnmount()。=>卸载(unmount)

调用顺序:

  1. 当组件传给React.render()时,React调用组件的构造函数constructor()初始化this.state。
  2. React调用render()方法。确定在该页面展示内容。更新DOM渲染输出。
  3. 当组件的输出插入到DOM后,调用componentDidMount()方法设置挂载时需运行的内容。
  4. 若需更新state,需在挂载内容时使用setState()方法更新state。并重新调用render()渲染更新过的数据,相应的更新DOM。
  5. 当组件从DOM移除,React调用componentWillUnmount()方法卸载。

state注意事项

  1. 更新state
    直接修改state不会重新渲染组件,如下:

    1
    2
    3
    4
    //此种修改不会渲染组件
    this.state.comment = "Hello";
    //使用setState才能达到更新目的
    this.setState({comment: 'Hello'});

    构造函数是唯一可以给this.state赋值的地方。

  2. state更新可能异步
    this.propsthis.state可能是异步更新的,故如下操作无法更新内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //wrong
    this.setState({
    counter: this.state.counter + this.props.increment,
    });
    //true
    //若想更新,可让setState()接受函数,而非对象。
    this.setState((state, props) => ({
    counter: state.counter + props.increment
    }));
    //不使用匿名箭头函数,使用普通函数也可
  3. state合并更新
    出于性能考虑,React可能会把多个setState()合并成一个调用。并将提供的对象合并到当前的state,进行部分替换,而非全局覆盖。
    如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    constructor(props){
    super(props);
    this.state = {
    posts: [],
    comments: []
    };
    }
    //更新posts时,只会替换posts部分,comments不变。更新comments同理。
    componentDidMount(){
    fetchPosts().then(response => {
    this.setState({posts: response.posts});
    });
    }
  4. 数据自顶向下
    无论父组件还是子组件都无法知道某组件是否有状态,且不关心是函数组件还是class组件。除了拥有并设置了state的组件,其他组件都无法访问。但组件可以选择把它的state作为props向下传递给它的子组件。从该state派生的任何数据或UI只能影响树中低于它的组件。
    每个组件都是真正独立的。

  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020-2024 Aweso Lynn
  • PV: UV: