zoukankan      html  css  js  c++  java
  • React的基本使用

    1、脚手架安装React项目

    安装 create-react-app 脚手架来创建 react 项目。

    npm install -g create-react-app
    create-react-app my-app

    使用该脚手架创建的 react 项目默认是不显示配置文件的,可以使用 npm run eject 命令将配置文件显示出来,该命令是一个单向操作,即一旦运行了,就不能再次将配置文件隐藏。

    2、JSX语法

    JSX是一种 JavaScript 的语法扩展,react 用它来声明 React 中的元素。你可以在 JSX 当中任意地使用 JavaScript 表达式,不过在 JSX 当中的表达式要包含在大括号里。

    //JSX语法
    const element = <h1>Hello, world!</h1>;
    
    function formatName(user) {
      return user.firstName + ' ' + user.lastName;
    }
    //在 JSX 中使用表达式
    const element = (
      <h1>
        Hello, {formatName(user)}!
      </h1>
    );
    
    // JSX 其实就是一个 JS 对象,你可以将它赋值给变量,或者当作参数传入、作为返回值都可以
    function getGreeting(user) {
      if (user) {
        return <h1>Hello, {formatName(user)}!</h1>;
      }
      return <h1>Hello, Stranger.</h1>;
    }

    在代码编译过后你可以看到 JSX 会被转化为普通的 JavaScript 对象,所以实际上,JSX 语法返回的是一个 JS 对象,这个对象也被称为 React 元素

    在 JSX 中我们可以放心地使用用户输入,因为React DOM 在渲染之前默认会过滤掉所有传入的值,它可以确保你的应用不会被注入攻击。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(跨站脚本) 攻击。

    const title = response.input;
    // 直接使用是安全的:
    const element = <h1>{title}</h1>;

    2.1、JSX 的属性

    在 JSX 中,可以使用引号来定义以字符串为值的属性,也可以使用大括号来定义以 JavaScript 表达式为值的属性

    const element = <div tabIndex="0"></div>;
    const element = <img src={user.avatarUrl}></img>;

    使用了大括号包裹的 JavaScript 表达式时就不要再到外面套引号了,因为JSX 会将引号当中的内容识别为字符串而不是表达式。

    2.2、更新元素渲染

    JSX 语法返回的是一个 JS 对象,这个对象也被称为 React 元素,元素是构成 React 应用的最小单位,在页面上进行渲染。

    要将React元素渲染到根DOM节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上

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

    React 元素都是不可变的。当元素被创建之后,我们无法改变其内容或属性。如果使用上面的方法,即使用元素来渲染页面,更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法替换之前的元素。当然,我们可以通过使用有状态组件(类定义组件)来避免这种落后的方法。

    3、组件

    3.1、定义组件

    组件可以接收任意的输入值(称之为“props”),并返回一个 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>;
      }
    }

    注意:组件的返回值只能有一个根元素。组件名称必须以大写字母开头。例如,<div /> 表示一个DOM标签,但 <Welcome /> 表示一个组件,并且在使用该组件时你必须定义或引入它。

    3.2、组件接收传入值(props)

    React 元素可以是DOM标签,也可以是用户自定义的组件,当 React 元素是用户自定义的组件,它会将 JSX 属性作为单个对象传递给该组件,这个对象称之为“props”。

    const element = <div />;
    //用户自定义的组件
    const element = <Welcome name="Sara" />;

    在组件中,不允许修改 props 的值,只允许读取。 

    4、类组件

    使用元素渲染或者是函数定义组件渲染来更新页面非常不方便,所以在一个 react 项目中我们应该使用类组件来渲染页面。使用类我们就可以使用它的一些特性,例如局部状态 state、生命周期钩子等,这大大方便了我们的开发。

     类组件代码示例:

    class Clock extends React.Component {
      constructor(props) {
        super(props);  //类组件应始终使用 props 调用基础构造函数。
        this.state = {date: new Date()};
      }
    
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }

    4.1、组件生命周期

    官网的组件生命周期图:

     我们可以在生命周期钩子上定义一些函数来进行一些操作,如下实现了一个每秒钟修改一次状态的效果:

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
      //组件挂载后运行
      componentDidMount() {
        //如果数据不渲染在页面上,你可以直接往类上添加字段,不需要添加到state上
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
      //组件卸载前运行
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      tick() {
        this.setState({
          date: new Date()
        });
      }
    
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Clock />,
      document.getElementById('root')
    );

    4.2、局部状态(state、setState)

    局部状态 state 用来维护组件内部数据,可以通过 this.state.propertyName 来获取数据。构造函数是唯一能够初始化 this.state 的地方。

    组件可以将它的状态作为属性传递给其子组件,但是除了拥有并设置它的组件外,其它组件不可访问另一个组件的状态,这就是为什么状态通常被称为局部或封装。

    在更改局部状态时,不要直接修改,而应该使用 setState 方法,否则 react 不会重新渲染组件。setState 方法只是将你返回的对象合并到局部状态 state 中,并且是浅合并,即返回的对象中提及到的属性会被完全替换,没有涉及到的属性不受影响。

    //Wrong 不要直接修改
    //this.state.comment = 'Hello';
    
    // 应当使用 setState() 方法
    this.setState({comment: 'Hello'});

    在利用当前状态和 props 的值来修改下一状态时,应该用一个函数来作为 setState 的参数。否则如果直接修改的话,有可能更改会没有效果,因为这两种值是异步更新的。

    // Wrong 不应该直接修改
    //this.setState({
    //  counter: this.state.counter + this.props.increment,
    //});
    
    //setState() 应该接受一个函数而不是一个对象。 该函数将接收先前的状态作为第一个参数,将props做为第二个参数:
    this.setState((prevState, props) => ({
      counter: prevState.counter + props.increment
    }));
    
    //或者使用常规函数
    this.setState(function(prevState, props) {
      return {
        counter: prevState.counter + props.increment
      };
    });

    4.3、父子组件传值及事件调用

    react 中父组件可以将数据作为子组件的属性进行传值,子组件通过 props 属性接收值。

    父组件可以监听子组件中的某个事件,子组件直接在内部触发 props 事件即可以触发父组件监听的事件,由此父组件可以进行响应。

    //子组件
    class Child extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
      }
    
      handleChange(e) {
        //子组件触发 props 事件
        this.props.onDataChange(e.target.value);
      }
    
      render() {
        const val = this.props.val;
        return (
            <input value={val} onChange={this.handleChange} />
        );
      }
    }
    //父组件
    class Calculator extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.state = {name: 'wen'};
      }
      //父组件将 onDataChange 传递给子组件即监听了该事件,当子组件触发该事件时,父组件触发 handleChange 事件
      handleChange(name) {
        this.setState({name});
      }
    
      render() {
        return (
          <div>
            <Child
              val={this.state.name} onDataChange={this.handleChange} />
          </div>
        );
      }
    }

    5、事件处理

    React 元素的事件函数命名采用驼峰式写法,这点跟普通 DOM 元素调用函数不太一样。

    <!- 普通 DOM 元素 -->
    <button onclick="activateLasers()">
      Activate Lasers
    </button>
    
    <!- react 语法 -->
    <button onClick={activateLasers}>
      Activate Lasers
    </button>

    在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为。你必须明确的使用 preventDefault

    <!- 普通 DOM 元素 -->
    <a href="#" onclick="console.log('The link was clicked.'); return false">
      Click me
    </a>
    
    <!- react 语法 -->
    function handleClick(e) {
        e.preventDefault();
        console.log('阻止默认行为');
    }
    return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
    );

    事件处理的 this 指针问题及如何绑定 this 可以参考:https://www.cnblogs.com/wenxuehai/p/11378229.html 

    5.1、给事件函数传递参数

    为事件处理函数传递额外的参数,下面两种方式是等价的:

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

    箭头函数传递参数时,事件对象必须显式的进行传递,但是通过 bind 的方式,事件对象及其它的一些参数将会被隐式的进行传递。

    通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e要排在所传递参数的后面

    preventPop(name, e){    //事件对象e要放在最后
       e.preventDefault();
       alert(name);
    }
    
    <a href="" onClick={this.preventPop.bind(this,'aaa')}>Click</a>

    6、条件渲染

    在 react 中,我们可以使用 if 语句、&& 运算符、三元运算符来实现条件渲染,主要就是通过运算符来控制元素是否显示。

    //if 语句控制是否渲染
    render() {
        let button = null;
        if (true) {
          button = <LogoutButton onClick={this.handleLogoutClick} />;
        } else {
          button = <LoginButton onClick={this.handleLoginClick} />;
        }
        return (
          <div>{button}</div>
        );
    }
    
    // &&运算符控制是否渲染,在react中,大括号{}内如果是false,会忽略并跳过,并不会渲染出来
    <div>
          <h1>Hello!</h1>
          {arr.length > 0 && <h2>aaa</h2> }
    </div>
    
    //三元运算符
    <div>
       {isLoggedIn ? (
          <LogoutButton/>
       ) : (
          <LoginButton />
       )}
    </div>

    如果不想让组件渲染,可以让 render 方法返回 null,组件的render方法返回null并不会影响该组件生命周期方法的回调。

    7、列表渲染

    在 react 中,可以使用 map 遍历方法来实现列表渲染。

    //可以生成一个 JSX 元素,然后将该 JSX 元素插入渲染
    function NumberList(props) {
      const numbers = [1,2,3,5,6];
      const listItems = numbers.map((number) =>
        <li key={number.toString()}>
          {number}
        </li>
      );
      return (
        <ul>{listItems}</ul>
      );
    }
    
    //或者直接在大括号中写遍历表达式,因为JSX允许在大括号中嵌入任何表达式
    function NumberList(props) {
      const numbers = props.numbers;
      return (
        <ul>
          {numbers.map((number) =>
            <ListItem key={number.toString()}
                      value={number} />
          )}
        </ul>
      );
    }

    7.1、列表渲染中的 key

    react 在使用列表渲染时,必须给每个列表元素分配一个 key,否则会出现一个警告 a key should be provided for list items。

    列表渲染时,key只需在兄弟元素之间唯一即可。react 在进行列表渲染时,数组元素中使用的 key 在其兄弟元素之间应该是独一无二的。然而,它们并不需要是全局唯一的,即如果不是同一列表兄弟元素的话,它们的 key 值是可以重复的。当我们在同一个页面中先后进行两次列表渲染时,我们可以使用相同的键。

    //同一组件中,不同列表元素,key值可以重复
    function Blog(props) {
      const sidebar = (
        <ul>
          {props.posts.map((post) =>
            <li key={post.id}>
              {post.title}
            </li>
          )}
        </ul>
      );
      const content = props.posts.map((post) =>
        <div key={post.id}>
          <h3>{post.title}</h3>
          <p>{post.content}</p>
        </div>
      );
      return (
        <div>
          {sidebar}
          <hr />
          {content}
        </div>
      );
    }
    
    const posts = [
      {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
      {id: 2, title: 'Installation', content: 'You can install React from npm.'}
    ];
    ReactDOM.render(
      <Blog posts={posts} />,
      document.getElementById('root')
    );

    8、表单元素

    8.1、受控组件

    使用受控组件可以将用户输入的值保存在组件的状态属性中,并且能控制用户输入时所发生的变化。

    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: ''};
        this.handleChange = this.handleChange.bind(this);
      }
    
      handleChange(event) {
        this.setState({value: event.target.value});
      }
    
      //必须要主动绑定 onChange 事件,并且修改 value 值,此时 value的值才会改变。react并没有像Vue那样有v-model的功能
      render() {
        return (
              <input type="text" value={this.state.value} onChange={this.handleChange} />
        );
      }
    }

    textarea、select标签写法都类似,可参考:https://www.reactjscn.com/docs/forms.html

    当有多个受控元素时,可以给每个元素都添加一个 name 属性,处理函数就可以根据 name 属性的值来进行相应操作,由此可以避免重复写处理函数。

    class Reservation extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          numberOfGuests: 2
        };
        this.handleInputChange = this.handleInputChange.bind(this);
      }
    
      handleInputChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;
        //可以这样设置状态
        this.setState({
          [name]: value
        });
      }
    
      render() {
        return (
            <input
               name="isGoing"
               type="checkbox"
               checked={this.state.isGoing}
               onChange={this.handleInputChange} />
            <input
               name="numberOfGuests"
               type="number"
               value={this.state.numberOfGuests}
               onChange={this.handleInputChange} />
        );
      }
    }

    8.2、非受控组件

    如果你觉得需要为每个表单元素绑定一个处理函数比较麻烦,你可以尝试使用非受控组件。非受控组件将真实数据保存在 DOM 中,我们可以使用 ref 从 DOM 中获取表单值。

    使用非受控组件可以减小代码量,但并不推荐使用,推荐还是使用受控组件。

    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    
      handleSubmit(event) {
        alert(this.input.value);
        event.preventDefault();
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
             <input type="text" ref={(input) => this.input = input} />
             <input type="submit" value="Submit" />
          </form>
        );
      }
    }

    非受控组件还可以指定元素初始值,使用 defaultValue 

    <input defaultValue="Bob" type="text" ref={(input) => this.input = input} />

    9、组合(插槽)

    在 react 中,可以通过使用 props.children 来实现类似于 Vue 中的插槽的功能。

    //子组件
    function FancyBorder(props) {
      return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
          {props.children}
        </div>
      );
    }
    
    //父组件
    function WelcomeDialog() {
      return (
        <FancyBorder>
          <h1>Welcome</h1>
        </FancyBorder>
      );
    }

    具名插槽:

    //子组件
    function SplitPane(props) {
      return (
        <div className="SplitPane">
          <div>
            {props.left}
          </div>
          <div>
            {props.right}
          </div>
        </div>
      );
    }
    
    //父组件
    function App() {
      return (
        <SplitPane
          left={
            <Contacts />
          }
          right={
            <Chat />
          } />
      );
    }

    上面的 <Contacts /> 和 <Chat /> 这样的 React 元素其实本质上都是对象,所以你可以像任何其他元素一样传递它们。使用具名插槽其实就是通过属性来传递数据,不过此时的数据是一个 react 元素而已。

  • 相关阅读:
    视频编码H.264的应用
    音视频的发展与anychat的技术
    Anychat 行业内最佳的跨平台音视频解决方案
    Android移动端音视频的快速开发教程(六)
    如何快速开发跨平台音视频应用软件
    音视频通讯SDK详解(附代码包)
    Python教学课程分享10-异常处理结构
    Python教学课程分享9-面向对象编程
    Python教学课程分享8-函数
    Python教学课程分享7-文件操作
  • 原文地址:https://www.cnblogs.com/wenxuehai/p/11374469.html
Copyright © 2011-2022 走看看