美文网首页
PHP的全栈之路3

PHP的全栈之路3

作者: foxman | 来源:发表于2018-01-06 14:27 被阅读10次

    死磕React 第一回

    上帝视角

    官网当然是我们最佳的学习资料,但我记得一句话,好老师从来都不是按照课本顺序来讲义的,所以对于官网上的文档,我觉得最佳的学习顺序也并非从头看到尾,我们首先要开启上帝视角

    为什么要有react呢,他解决了一类什么问题?
    React 理念这篇官网的文章让我找到了一些答案,水平有限,我只读懂了文章里的第一步、第二步,后面就开始晕了,建议第一次接触的人也不要急于全部搞懂,这篇文章给我两个很重要的信息。

    • 前端分层解决方案——组件
      第一次让我见识到,原来前端不再是像以前那样,写一大串html,来完成整个页面的静态编码,而是将页面切割成不同的部分,用组件来表示页面的元素
    • 组件的实现方式——react
      react是什么呢?我认为它就是组件的一种实现方式之一,组件是一种思想,落实到编码实现上,就是react了,react也就显的不再那么高深了,由此我还能猜想到Vue和Angular无非就是组件的另外两种实现方式而已

    了解概念

    接下来就要撸一堆概念了,建议撸完本文后,可以官网上撸概念

    组件

    将UI切分成一些的独立的、可复用的部件,这样你就只需专注于构建每一个单独的部件,这样的部件称为组件,在React中有其特有的语法表示,组件从概念上看就像是函数,它可以接收任意的输入值(称之为“props”),并返回一个需要在页面上展示的React元素

    函数定义/类定义组件

    定义一个组件最简单的方式是使用JavaScript函数:

    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
    

    它接收一个单一的“props”对象并返回了一个React元素,可能你会对这句话里的propsReact元素理解起来困难,没关系,就将其当成PHP里的参数和返回值好了。

    你也可以使用 ES6 class 来定义一个组件:

    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    

    上面两个组件在React中是相同的,我就当第一种是过程编程,第二种是对象编程吧,这样有助于我记忆,毕竟利用学过的知识来映射新的知识,这样能更清楚的记住

    组合组件

    组件可以在它的输出中引用其它组件,这就可以让我们用同一组件来抽象出任意层次的细节。在React应用中,按钮、表单、对话框、整个屏幕的内容等,这些通常都被表示为组件。
    我们可以创建一个App组件,用来多次渲染Welcome组件:

    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
    
    function App() {
      return (
        <div>
          <Welcome name="Sara" />
          <Welcome name="Cahal" />
          <Welcome name="Edite" />
        </div>
      );
    }
    
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
    

    警告:组件的返回值只能有一个根元素。这也是我们要用一个<div>来包裹所有<Welcome />元素的原因。

    元素

    上面我们提到一个组件会返回一个React元素,所谓元素是构成 React 应用的最小单位,元素用来描述我们在屏幕上看到的内容:

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

    与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致

    元素渲染到 DOM 中

    首先我们在一个 HTML 页面中添加一个 id="root" 的 <div>:

    <div id="root"></div>
    

    在此 div 中的所有内容都将由 React DOM 来管理,所以我们将其称之为 “根” DOM 节点。

    我们将 元素传入一个名为 ReactDOM.render() 的方法来将其渲染到页面上:

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

    Props&纯函数

    上文中我们搁置了对Props的解释,只是暂且看作PHP函数的参数来理解,实际上也是如此。

    对于函数声明的组件,props就是外部使用组件时,传入组件的参数

    // Welcome组件通过props.name拿到调用者传入的数据
    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
    
    // 组件App 返回一个react元素,元素中使用了Welcome组件,并将name属性传入组件
    function App() {
      return (
        <div>
          <Welcome name="Sara" />
        </div>
      );
    }
    
    // 渲染App组件到DOM中
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
    
    /*output
    <h1>Hello, Sara</h1>
    */
    

    对于类声明的组件,props就是类的一个属性,通过这个属性能取到外部使用组件时,传入组件的一些必要数据

    // Welcome组件通过this.props.name拿到调用者传入的数据
    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    
    // 组件App 返回一个react元素,元素中使用了Welcome组件,并将name属性传入组件
    function App() {
      return (
        <div>
          <Welcome name="Sara" />
        </div>
      );
    }
    
    // 渲染App组件到DOM中
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
    
    /*output
    <h1>Hello, Sara</h1>
    */
    

    当然这还不是全部,Props相比一般的参数,具有只读性,也就是其值不会被改变,这里正好引入了纯函数和非纯函数的概念

    function sum(a, b) {
      return a + b;
    }
    

    类似于上面的这种函数称为“纯函数”,它没有改变它自己的输入值,当传入的值相同时,总是会返回相同的结果

    与之相对的是非纯函数,它会改变它自身的输入值:

    function withdraw(account, amount) {
      account.total -= amount;
    }
    

    React是非常灵活的,但它也有一个严格的规则:
    所有的React组件必须像纯函数那样使用它们的props

    State&生命周期

    应用的界面是随时间动态变化的,State可以在不违反props规则的情况下,根据用户操作、网络响应、或者其他状态变化,使组件动态的响应并改变组件的输出

    我们在定义组件的时候,虽然可以通过函数和类声明这两种方式,但是当涉及到局部状态、生命周期钩子等高级用法时,只能通过类的方式来声明组件

    官网的例子写的非常详细,细致的说出了其演变,我重新再拜读下官网例举的定时器例子,并试着给代码用1、2、3标注执行的顺序,加上注释

    class Clock extends React.Component {
      // 2. 组件被外部调用时,会优先执行构造函数,这里是初始化this.state的地方
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
    
      // 4. 当组件返回的元素输出到屏幕时,调用此钩子设置一个定时器,每秒钟调用一次tick()
      componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      // 6. 一旦Clock组件被从DOM中移除,会调用这个钩子函数清除定时器
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      /* 5. 调用tick()方法,通过使用包含当前时间的对象调用setState()来调度UI更新。
            通过调用setState() ,React 知道状态已经改变,并再次调用render()方法
            来确定屏幕上应当显示什么。这一次,render()方法中的this.state.date将不同,
            所以渲染输出将包含更新的时间,并相应地更新DOM。
      */
      tick() {
        this.setState({
          date: new Date()
        });
      }
    
      // 3. 随后render方法被调用,将Clock组件返回的元素输出到屏幕
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    
    // 1. 渲染Clock组件
    ReactDOM.render(
      <Clock />,
      document.getElementById('root')
    );
    

    我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码

    上例中的componentDidMountcomponentWillUnmount这些方法被称作生命周期钩子,分别在组件输出到 DOM 后、组件从DOM中移除时执行

    正确地使用状态

    关于 setState() 这里有三件事情需要知道

    1. 不要直接更新状态

    例如,此代码不会重新渲染组件:

    // Wrong
    this.state.comment = 'Hello';
    

    应当使用 setState():

    // Correct
    this.setState({comment: 'Hello'});
    

    构造函数是唯一能够初始化 this.state 的地方。

    1. 状态更新可能是异步的

    React 可以将多个setState() 调用合并成一个调用来提高性能。

    因为 this.propsthis.state 可能是异步更新的,你不应该依靠它们的值来计算下一个状态。

    例如,此代码可能无法更新计数器:

    // Wrong
    this.setState({
      counter: this.state.counter + this.props.increment,
    });
    
    

    要修复它,请使用第二种形式的 setState() 来接受一个函数而不是一个对象。 该函数将接收先前的状态作为第一个参数,将需要更新的值作为第二个参数:

    // Correct
    this.setState((prevState, props) => ({
      counter: prevState.counter + props.increment
    }));
    
    

    上方代码使用了箭头函数,但它也适用于常规函数:

    // Correct
    this.setState(function(prevState, props) {
      return {
        counter: prevState.counter + props.increment
      };
    });
    
    1. 状态更新合并

    当你调用 setState() 时,React 将你提供的对象合并到当前状态。例如,你的状态可能包含一些独立的变量:

      constructor(props) {
        super(props);
        this.state = {
          posts: [],
          comments: []
        };
      }
    

    你可以调用 setState() 独立地更新它们:

      componentDidMount() {
        fetchPosts().then(response => {
          this.setState({
            posts: response.posts
          });
        });
    
        fetchComments().then(response => {
          this.setState({
            comments: response.comments
          });
        });
      }
    

    这里的合并是浅合并,也就是说this.setState({comments})完整保留了this.state.posts,但完全替换了this.state.comments

    相关文章

      网友评论

          本文标题:PHP的全栈之路3

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