美文网首页
React的Hello World

React的Hello World

作者: 李霖弢 | 来源:发表于2020-05-11 17:59 被阅读0次
    VSCode配置语法高亮

    安装Babel JavaScript插件

    创建项目

    npx create-react-app my-app
    cd my-app
    npm start
    
    其他还有

    npm run build打包项目
    npm run eject弹射配置文件
    此外在package.json中添加"homepage": ".",可以让打包后的资源路径都变为相对index.html


    JSX

    JSX并不是单纯的将{}中内容替换后的HTML

    • 属性名均为小驼峰且部分有所变化,如JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex
    • 自定义属性依然为data-*形式,并可通过dom元素的dataset属性获取
    • {}中的内容默认会进行转义,因此不用担心XSS攻击
    • 没有内容的标签可以使用/> 来闭合。
    • style内容变为对象形式,且key变为小驼峰
    • 图片等资源可以通过以下四种方式引入
      1. import Img from "./images/1.png" <img src={Img} alt=""/>
      2. <img src={require("./images/1.png")} alt=""/>
      3. style={{background:"url("+require("./images/1.png")+")" }}
      4. <img src={process.env.PUBLIC_URL + "/logo512.png"} />;
        其中process.env.PUBLIC_URL等同于index.html中的%PUBLIC_URL%表示public目录,start和build时webpack会将其替换为实际路径

    所有JSX其实都是React.createElement() 的语法糖,通过Babel 可以进行转义。

    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    

    等同于

    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
    

    渲染

    通过render方法将react元素初始化并渲染到页面上

      ReactDOM.render(
        element,
        document.getElementById('root')
      );
    

    其中element可以直接为上文中新建的元素,也可以为元素对应的组件标签,如<MyTest />


    组件

    接受任意的属性作为入参(即 props),并返回用于描述页面展示内容的 React 元素。

    • 组件必须为大驼峰命名,小写字母开头的组件会被视为原生 DOM 标签。
    • 通常将 App 组件 作为每个新的 React 应用程序的顶层组件。
    • 父元素需传元素给子元素时,可以在子组件标签间写入元素并通过props.children获取,或直接将待传入元素作为属性赋予子元素并通过props获取(类似插槽slot)
    函数组件与 class 组件
    function Welcome(props) {
      return element;
    }
    

    class组件中每次组件更新都会重新触发render

    class Welcome extends React.Component {
      render() {
        return element;
      }
    }
    
    react元素也可以是自定义组件
    const name="Sara";
    function Welcome_Fn(props) {
      function speak(e) {
        e.preventDefault();
        alert(this.props.name);
      }
      return <h1 onClick={speak}>Hello, {props.name}</h1>;
    }
    
    class Welcome_Class extends React.Component {
      speak() {
        alert(this.props.name);
      }
      render() {
        return <div onClick={onClick=()=>this.speak()}>Hello, {this.props.name}</div>;
      }
    }
    
    const element = <Welcome_Class name="Sara" />;
    ReactDOM.render(
      //element,
      //<Welcome_Class/>,
      //<Welcome_Fn/>,
      //new Welcome_Class({name}),
      //new Welcome_Fn({name}),
      <div>Hello, {name}</div>,
      document.getElementById('root')
    );
    
    props
    • 组件的属性传入为 props
    • 所有 React 组件都必须像纯函数(入参不会被函数内容修改)一样保护它们的 props 不被更改,会发生变化的数据应使用state
    state
    • props 类似,但是 state 是私有的,并且完全受控于当前组件。
    • 无需使用state的情况下可省略constructor
    • 构造函数是唯一可以对this.state赋值的地方,其他场合仅可使用this.setState()(类似wx小程序)
    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
      componentDidMount() {
        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')
    );
    
    • 出于性能考虑,React 可能会把多个 setState() 合并成一个,因此setState()可能是异步的,this.propsthis.state 可能会异步更新,setState()时不要直接使用他们的值,而是用一个函数作为入参
    this.setState((state, props) => ({
      counter: state.counter + props.increment
    }));
    //或
    this.setState(function(state, props) {
      return {
        counter: state.counter + props.increment
      };
    });
    
    自上而下的单向数据流

    多重组件嵌套时,通常将父的state传递给子的props,任何的 state总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。


    事件处理

    React 事件的命名采用小驼峰式而非纯小写,且在JSX中需传入一个事件处理函数。

    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }
    
    • 事件的默认参数e已做过跨浏览器兼容处理,直接使用 e.preventDefault();即可统一阻止默认事件。
    使用class组件时的方法内this指向问题

    可类比以下操作

    class A {
      handleClick1 = () => {
        console.log(this, "handleClick1");
      }
      handleClick2() {
        console.log(this, "handleClick2");
      }
      render() {
        window.addEventListener("click", this.handleClick1);//A
        window.addEventListener("click", this.handleClick2);//window
      }
    }
    new A().render();
    

    因此有三种方法避免this指向问题

    1. 构造函数中使用bind
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
      }
    
    1. 使用class fields语法
      handleClick = () => {
        console.log(this);
      }
    
    1. 在回调中使用()=>bind
    • ()=>
    <button onClick={(e) => this.handleClick(id, e)}>Click me</button>
    
    • bind
    handleClick(id,event){
      ...
    }
    <button onClick={this.handleClick.bind(this, id)}>Click me</button>
    

    条件渲染

    当不想进行任何渲染时,可以return null

    &&
    function Mailbox(props) {
      const unreadMessages = props.unreadMessages;
      return (
        <div>
          <h1>Hello!</h1>
          {unreadMessages.length > 0 &&
            <h2>
              You have {unreadMessages.length} unread messages.
            </h2>
          }
        </div>
      );
    }
    
    
    ?:
    render() {
      const isLoggedIn = this.state.isLoggedIn;
      return (
        <div>
          The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
        </div>
      );
    }
    

    列表 & Key

    列表中的内容是一个React元素的数组,以下两种方式均可生成一个列表
    注意列表中必须有key,未指定key时key默认为索引值

    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    
    function NumberList(props) {
      const numbers = props.numbers;
      return (
        <ul>
          {numbers.map((number) =>
            <ListItem key={number.toString()}
                      value={number} />
          )}
        </ul>
      );
    }
    

    表单

    React中未实现双向绑定

    受控组件
    class Reservation extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          fruit: "lime"
        };
    
        this.handleChange= this.handleChange.bind(this);
      }
    
      handleChange(event) {
        const target = event.target;
        const value = target.name === 'isGoing' ? target.checked : target.value;
        const name = target.name;
        this.setState({
          [name]: value
        });
      }
    
      render() {
        return (
          <form>
              <input
                name="isGoing"
                type="checkbox"
                checked={this.state.isGoing}
                onChange={this.handleChange} />
    
              <select name="fruit" value={this.state.fruit} onChange={this.handleChange}>
                <option value="grapefruit">葡萄柚</option>
                <option value="lime">酸橙</option>
                <option value="coconut">椰子</option>
                <option value="mango">芒果</option>
              </select>
          </form>
        );
      }
    }
    
    非受控组件
    • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。
    • 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
    class FileInput extends React.Component {
      constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.fileInput = React.createRef();
      }
      handleSubmit(event) {
        event.preventDefault();
        alert(
          `Selected file - ${this.fileInput.current.files[0].name}`
        );
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              Upload file:
              <input type="file" ref={this.fileInput} />
            </label>
            <br />
            <button type="submit">Submit</button>
          </form>
        );
      }
    }
    
    ReactDOM.render(
      <FileInput />,
      document.getElementById('root')
    );
    
    使用 Formik

    状态提升

    将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,以实现共享 state

    实现方式

    父元素通过props将待展示的值和该值变化时的回调方法传给子元素。子元素调用该回调时,父元素对应state改变,并重新影响各个子元素。以此实现兄弟元素间的值共享。


    打包

    在package.json中加入"homepage": ".",即可使打包后资源路径变为相对路径(否则默认为绝对路径)。

    相关文章

      网友评论

          本文标题:React的Hello World

          本文链接:https://www.haomeiwen.com/subject/ynqpnhtx.html