關于React你應該了解的一切:開始構建前你所需的基礎知識

wxl9521 7年前發布 | 30K 次閱讀 React

摘要: 你是不是對React充滿好奇,并且還沒有機會學習它?或者你已經嘗試過,卻掙扎于核心概念的掌握?又或者你已經學習過基礎,但是想鞏固一下知識?無論你是以上哪種類型,這篇文章都適合你。我們要基于以下的全新React概念構建一個簡單的React音樂播放器。

關于React你應該了解的一切:開始構建前你所需的基礎知識

本文由VicSusi在眾成翻譯平臺翻譯。

你是不是對React充滿好奇,并且還沒有機會學習它?或者你已經嘗試過,卻掙扎于核心概念的掌握?又或者你已經學習過基礎,但是想鞏固一下知識?無論你是以上哪種類型,這篇文章都適合你。

我們要基于以下的全新React概念構建一個簡單的React音樂播放器。

下面是我們要了解的內容:

  • 什么是React組件?
  • ReactDOM渲染
  • 類 vs 函數化組件
  • JSX
  • 狀態
  • 事件操作
  • 異步設置狀態
  • 屬性
  • 文件系統

以上是構建和維護一個React應用你需要了解的知識。但我們打算按部分來介紹。

設置

現在情況是這樣:你要完成一個小小的任務。他們創建了用戶上傳音樂的頁面,并用醒目的顏色讓頁面更加直觀。但他們需要你來完成困難的部分-就是指讓這個頁面正常工作。

開始前,創建一個新的項目目錄,添加 以下的三個文件 .

app.css

body {

<pre>  background: #f9f9f9;
  font-family: 'Open Sans', sans-serif;
  text-align: center;
}

#container {
  position: relative;
  z-index: 2;
  padding-top: 100px;
}

.play {
  display: block;
  width: 0;
  height: 0;
  border-top: 50px solid transparent;
  border-bottom: 50px solid transparent;
  border-left: 60px solid #2c3e50;
  margin: 100px auto 50px auto;
  position: relative;
  z-index: 1;
  transition: all 0.3s;
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
  left: 10px;
}

.play:before {
  content: '';
  position: absolute;
  top: -75px;
  left: -115px;
  bottom: -75px;
  right: -35px;
  border-radius: 50%;
  border: 10px solid #2c3e50;
  z-index: 2;
  transition: all 0.3s;
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
}
.play:after {
  content: '';
  opacity: 0;
  transition: opacity 0.6s;
  -webkit-transition: opacity 0.6s;
  -moz-transition: opacity 0.6s;
}
.play:hover:before, .play:focus:before {
  transform: scale(1.1);
  -webkit-transform: scale(1.1);
  -moz-transform: scale(1.1);
}
.play.active {
  border-color: transparent;
}
.play.active:after {
  content: '';
  opacity: 1;
  width: 25px;
  height: 80px;
  position: absolute;
  right: 8px;
  top: -40px;
  border-right: 20px solid #2c3e50;
  border-left: 20px solid #2c3e50;
}

h1 {
  text-transform: uppercase;
  color: #34495e;
  letter-spacing: 2px;
  font-size: 2em;
  margin-bottom: 0;
}

canvas {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

audio {
  position: fixed;
  left: 10px;
  bottom: 10px;
  width: calc(100% - 20px);
}
</pre>

<div>```</div>

<div>app.js</div>

<div>```</div>

<div>

<pre>var ALPHA,
  AudioAnalyser,
  COLORS,
  MP3_PATH,
  NUM_BANDS,
  NUM_PARTICLES,
  Particle,
  SCALE,
  SIZE,
  SMOOTHING,
  SPEED,
  SPIN,
  TIMES_CALLED,
  ANALYSER;

NUM_PARTICLES = 150;

NUM_BANDS = 128;

TIMES_CALLED = 0;

SMOOTHING = 0.5;

MP3_PATH = 'music.mp3';

SCALE = {
  MIN: 5.0,
  MAX: 80.0
};

SPEED = {
  MIN: 0.2,
  MAX: 1.0
};

ALPHA = {
  MIN: 0.8,
  MAX: 0.9
};

SPIN = {
  MIN: 0.001,
  MAX: 0.005
};

SIZE = {
  MIN: 0.5,
  MAX: 1.25
};

COLORS = [
  '#69D2E7',
  '#1B676B',
  '#BEF202',
  '#EBE54D',
  '#00CDAC',
  '#1693A5',
  '#F9D423',
  '#FF4E50',
  '#E7204E',
  '#0CCABA',
  '#FF006F'
];
function getAnimation(file) {
  AudioAnalyser = (function() {
    AudioAnalyser.AudioContext = self.AudioContext || self.webkitAudioContext;

    AudioAnalyser.enabled = AudioAnalyser.AudioContext != null;

    function AudioAnalyser(audio, numBands, smoothing) {
      var src;
      this.audio = audio != null ? audio : new Audio();
      this.numBands = numBands != null ? numBands : 256;
      this.smoothing = smoothing != null ? smoothing : 0.3;
      this.audio = document.getElementById('audio');
      if (!this.audio) {
        return;
      }
      try {
        this.audio.src = window.URL.createObjectURL(file);
      } catch (err) {
        console.log(err);
      }
      this.context = new AudioAnalyser.AudioContext();
      this.jsNode = this.context.createScriptProcessor(2048, 1, 1);
      this.analyser = this.context.createAnalyser();
      this.analyser.smoothingTimeConstant = this.smoothing;
      this.analyser.fftSize = this.numBands * 2;
      this.bands = new Uint8Array(this.analyser.frequencyBinCount);
      this.audio.addEventListener(
        'play',
        (function(_this) {
          return function() {
            if (TIMES_CALLED === 1) {
              return;
            }
            ANALYSER.start();
            TIMES_CALLED++;
            _this.source = _this.context.createMediaElementSource(_this.audio);
            _this.source.connect(_this.analyser);
            _this.analyser.connect(_this.jsNode);
            _this.jsNode.connect(_this.context.destination);
            _this.source.connect(_this.context.destination);
            return (_this.jsNode.onaudioprocess = function() {
              _this.analyser.getByteFrequencyData(_this.bands);
              if (!_this.audio.paused) {
                return typeof _this.onUpdate === 'function'
                  ? _this.onUpdate(_this.bands)
                  : void 0;
              }
            });
          };
        })(this)
      );
    }

    AudioAnalyser.prototype.start = function() {
      return this.audio.play();
    };

    AudioAnalyser.prototype.stop = function() {
      return this.audio.pause();
    };

    return AudioAnalyser;
  })();

  Particle = (function() {
    function Particle(x1, y1) {
      this.x = x1 != null ? x1 : 0;
      this.y = y1 != null ? y1 : 0;
      this.reset();
    }

    Particle.prototype.reset = function() {
      this.level = 1 + floor(random(4));
      this.scale = random(SCALE.MIN, SCALE.MAX);
      this.alpha = random(ALPHA.MIN, ALPHA.MAX);
      this.speed = random(SPEED.MIN, SPEED.MAX);
      this.color = random(COLORS);
      this.size = random(SIZE.MIN, SIZE.MAX);
      this.spin = random(SPIN.MAX, SPIN.MAX);
      this.band = floor(random(NUM_BANDS));
      if (random() < 0.5) {
        this.spin = -this.spin;
      }
      this.smoothedScale = 0.0;
      this.smoothedAlpha = 0.0;
      this.decayScale = 0.0;
      this.decayAlpha = 0.0;
      this.rotation = random(TWO_PI);
      return (this.energy = 0.0);
    };

    Particle.prototype.move = function() {
      this.rotation += this.spin;
      return (this.y -= this.speed * this.level);
    };

    Particle.prototype.draw = function(ctx) {
      var alpha, power, scale;
      power = exp(this.energy);
      scale = this.scale * power;
      alpha = this.alpha * this.energy * 1.5;
      this.decayScale = max(this.decayScale, scale);
      this.decayAlpha = max(this.decayAlpha, alpha);
      this.smoothedScale += (this.decayScale - this.smoothedScale) * 0.3;
      this.smoothedAlpha += (this.decayAlpha - this.smoothedAlpha) * 0.3;
      this.decayScale *= 0.985;
      this.decayAlpha *= 0.975;
      ctx.save();
      ctx.beginPath();
      ctx.translate(this.x + cos(this.rotation * this.speed) * 250, this.y);
      ctx.rotate(this.rotation);
      ctx.scale(
        this.smoothedScale * this.level,
        this.smoothedScale * this.level
      );
      ctx.moveTo(this.size * 0.5, 0);
      ctx.lineTo(this.size * -0.5, 0);
      ctx.lineWidth = 1;
      ctx.lineCap = 'round';
      ctx.globalAlpha = this.smoothedAlpha / this.level;
      ctx.strokeStyle = this.color;
      ctx.stroke();
      return ctx.restore();
    };

    return Particle;
  })();

  Sketch.create({
    particles: [],
    setup: function() {
      var analyser, error, i, intro, j, particle, ref, warning, x, y;
      for (i = j = 0, ref = NUM_PARTICLES - 1; j <= ref; i = j += 1) {
        x = random(this.width);
        y = random(this.height * 2);
        particle = new Particle(x, y);
        particle.energy = random(particle.band / 256);
        this.particles.push(particle);
      }
      if (AudioAnalyser.enabled) {
        try {
          analyser = new AudioAnalyser(MP3_PATH, NUM_BANDS, SMOOTHING);
          analyser.onUpdate = (function(_this) {
            return function(bands) {
              var k, len, ref1, results;
              ref1 = _this.particles;
              results = [];
              for (k = 0, len = ref1.length; k < len; k++) {
                particle = ref1[k];
                results.push((particle.energy = bands[particle.band] / 256));
              }
              return results;
            };
          })(this);
          analyser.audio = window.audio;
          ANALYSER = analyser;
          intro = document.getElementById('intro');
          intro.style.display = 'none';
          if (
            /Safari/.test(navigator.userAgent) &&
            !/Chrome/.test(navigator.userAgent)
          ) {
            warning = document.getElementById('warning2');
            return (warning.style.display = 'block');
          }
        } catch (_error) {
          error = _error;
        }
      } else {
        warning = document.getElementById('warning1');
        return (warning.style.display = 'block');
      }
    },
    draw: function() {
      var j, len, particle, ref, results;
      this.globalCompositeOperation = 'lighter';
      ref = this.particles;
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        particle = ref[j];
        if (particle.y < -particle.size * particle.level * particle.scale * 2) {
          particle.reset();
          particle.x = random(this.width);
          particle.y =
            this.height + particle.size * particle.scale * particle.level;
        }
        particle.move();
        results.push(particle.draw(this));
      }
      return results;
    }
  });
}

function handleFileSelect(evt) {
  var files = evt.target.files;
  getAnimation(files[0]);
}

getAnimation(null);

document
  .getElementById('files')
  .addEventListener('change', handleFileSelect, false);</pre>

</div>

<div>```</div>

<div>index.html</div>

<div>
<link rel="stylesheet" href="app.css">
<link rel="stylesheet" >

Play Music

<input type="file" id="files" name="files[]" multiple />

`<script crossorigin src="https://unpkg.com/react@15/dist/react.js">`</script> `<script crossorigin src="https://unpkg.com/react-dom@15/dist/react-dom.js">`</script> `<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js">`</script> `<script src="https://soulwire.github.io/sketch.js/js/sketch.min.js">`</script> `<script src="app.js">`</script> `<script type="text/babel">` // React code goes here. </script>

```

確定你使用了最新版 chrome ,不然代碼中的動畫效果無法呈現

謝謝 Steven Fabre 提供的播放按鈕CSS代碼,還有 Justin Windle 提供的可視化代碼( 你可以在這里查看代碼 )

在代碼編輯器里打開index.html,讓我們開始吧!

什么是React?

React是構建用戶界面的一種方式。它只和你在前端所見的相關。React通過把每個頁面切分為小塊讓用戶界面變得易于構建。我們把這些小塊叫做組件。

這里有一個把頁面切分為組件的例子:

關于React你應該了解的一切:開始構建前你所需的基礎知識

每個高亮的部分都被視為一個組件。可這對于開發者意味著什么呢?

什么是React組件?

一個React組件就是一個代表頁面某部分的代碼塊。每個組件都是一個JS函數,這個函數返回的代碼表示一個web頁面的一部分。

為了構建一個頁面,我們將按一定順序調用這些函數,然后把結果放在一起展示給用戶。

讓我們在index.html中寫一個type="text/babel"的組件:

<script type="text/babel">`
  function OurFirstComponent() {
    return (
      // Code that represents the UI element goes here
    );
  }
</script>

當我們調用OurFirstcomponent()函數,我們會得到頁面的一個部分。

你可以像下面這樣編寫函數:

const OurFirstComponent = () => {
  return (
    // Stuff to make this component goes here
  );
}

React使用了JSX語言,它看起來像HTML但在JS里運行,HTML可不經常這么做。

你可以為這部分添加無樣式的HTML,這樣就可以在UI上顯示了:

<script type="text/babel">`
  function OurFirstComponent() {
    return (
      <h1>Hello, I am a React Component!</h1>
    );
  }
</script>

When we call the OurFirstComponent() function, we get back a bit of JSX. We can use something called ReactDOM to put it on the page.

當我們調用OurFirstComponent函數,我們得到一些JSX代碼。我們可以使用 ReactDOM 把它們放在頁面上。

<script type="text/babel">`
  function OurFirstComponent() {
    return (
      <h1>Hello, I am a React Component!</h1>
    );
  }
**const placeWeWantToPutComponent = document.getElementById('hook');
  ReactDOM.render(OurFirstComponent(), placeWeWantToPutComponent);**
</script>

現在通過ID我們會將標簽放入元素中。當你刷新瀏覽器時它看起來應該是這樣:

關于React你應該了解的一切:開始構建前你所需的基礎知識

我們可以像這樣用JSX編寫組件:

ReactDOM.render(<OurFirstComponent />, placeWeWantToPutComponent);

這是標準-調用組件就像編寫HTML,效果是一樣的。

把組件放在一起

我們可以把React組件放在其他組件里。

<script type="text/babel">`
  function OurFirstComponent() {
    return (
      **<h1>I am the child!</h1>**
    );
  }
**function Container() {
    return (
      <div>
        <h1>I am the parent!</h1>
        <OurFirstComponent />
      </div>
    );
  }**
const placeWeWantToPutComponent = document.getElementById('hook');
  ReactDOM.render(**<Container />**, placeWeWantToPutComponent);
</script>

關于React你應該了解的一切:開始構建前你所需的基礎知識

我們就是這樣通過React組件構造頁面的-通過組件嵌套組件實現。

類組件

到目前為止,我們一直在像編寫函數一樣編寫組件。它們被稱為函數式組件.

但你也可以用另一種方式編寫組件,比如JavaScript類。這樣編寫的組件被稱作類組件。

class Container extends React.Component {
  render() {
    return (
      <div>
        <h1>I am the parent!</h1>
        <OurFirstComponent />
      </div>
    );
  }
}
const placeWeWantToPutComponent = document.getElementById('hook');
ReactDOM.render(<Container />, placeWeWantToPutComponent);

類組件一定要有一個render()函數.這個渲染函數返回組件的JSX代碼。它們和函數化組件的使用方法相同。

你應該更多地使用函數化組件而不是類組件,因為前者更容易閱讀,除非你需要組件狀態(稍后介紹)

JSX中的JavaScript

你可以把JavaScript變量這樣放進你的JSX中:

class Container extends React.Component {
  render() {
    **const greeting = 'I am a string!';**
    return (
      <div>
        **<h1>{ greeting }</h1>**
        <OurFirstComponent />
      </div>
    );
  }
}

現在I am a string會在h1標簽內出現。

你也可以做點更難的,比如調用一個函數:

class Container extends React.Component {
  render() {
    **const addNumbers = (num1, num2) => {
      return num1 + num2;
    };**
    return (
      <div>
        **<h1>The sum is: { addNumbers(1, 2) }</h1>**
        <OurFirstComponent />
      </div>
    );
  }
}

關于React你應該了解的一切:開始構建前你所需的基礎知識

JSX可伸縮性

將OurFirstComponent()更名為PlayButton。我們想要它返回下面的內容:

<a href="#" title="Play video" />

可現在有個問題:class在JavaScript中是關鍵字,所以我們無法使用它。那我們該如何創建一個示例?

用一個名字叫className的屬性代替:

<script type="text/babel">`
 **function PlayButton() {
    return <a href="#" title="Play video" />;
  }**
class Container extends React.Component {
    render() {
      return (
        <div>
          **<PlayButton />**
        </div>
      );
    }
  }
const placeWeWantToPutComponent = document.getElementById('hook');
  ReactDOM.render(<Container />, placeWeWantToPutComponent);
</script>

這個組件在干什么?

類組件可以存儲關于它們最近狀態的信息。這個信息被稱為狀態,儲存在一個JavaScript對象中。

下面的代碼里,有一個對象代表我們組件的狀態。對象有一個鍵名叫isMusicPlaying,值為false。這個對象被以建造者模式分配給this.state,當這個類首次使用時this.state被調用。

class Container extends React.Component {
  **constructor(props) {
    super(props);
    this.state = { isMusicPlaying: false };
  }**

  render() {
    return (
      <div>
        <PlayButton />
      </div>
    );
  }
}

一個React組件的建造者模式總是需要在最開始就調用super(props)。

好,那我們要狀態干什么呢?為什么它會存在?

基于狀態改變我們的React組件

可以基于事件的狀態來更新我們的UI。

在本文中,我們會基于用戶點擊播放按鈕的操作,利用狀態實現播放按鈕從停止到播放的改變。

當用戶點擊按鈕,狀態就會更新,然后UI就會更新。

我們按下面的步驟開始。我們可以利用this,state監視組件狀態。下面的代碼中,我們持續監視狀態并根據它來決定展示給用戶什么樣的內容。

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isMusicPlaying: false };
  }
render() {
    **const status = this.state.isMusicPlaying ? 'Playing' : 'Not playing';**
    return (
      <div>
        **<h1>{ status }</h1>**
        <PlayButton />
      </div>
    );
  }
}

在這個渲染函數中,this經常表示它所在的組件。

關于React你應該了解的一切:開始構建前你所需的基礎知識

但這并沒有什么用處,除非我們有方法可以改變this.state.isMusicPlaying。

當我們的組件發生變化的時候

用戶可以通過點擊播放按鈕與我們的組件實現交互。我們想對這些事件做出反應(ha...ha...)。

我們通過與事件相關的函數實現交互操作。我們稱之為事件句柄。

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isMusicPlaying: false };
  }
**handleClick(event) {
    // Do something about the click
  };**
render() {
    let status = this.state.isMusicPlaying 
    ? 'Playing :)' 
    : 'Not playing :(';
    return (
      <div>
        <h1>{ status }</h1>
        <PlayButton />
      </div>
    );
  }
}

當用戶點擊h1時,我們的組件會運行handleClick函數。這個函數將得到的時間對象作為參數,這意味著它可以隨心所欲地使用該對象。

我們在handleClick上使用.bind方法,以確保this特指整個組件,而不只是h1。

那這個組件應該干什么

當我們改變了組件的狀態,它會再次調用渲染函數。

我們可以隨this.setState()改變狀態,只要我們給它一個表示新狀態的新對象。

我們頁面中的組件會始終展示它們的最新狀態。這是React替我們做的。

handleClick() {
    **if (this.state.isMusicPlaying) {
      this.setState({ isMusicPlaying: false });
    } else {
      this.setState({ isMusicPlaying: true });
    }**
  };

可是點擊一個h1還是不如點擊播放按鈕方便。讓我們動手實現一下吧。

組件間的通信

你的組件可以互相通信。讓我們試一下。

我們可以用屬性告知播放按鈕音樂是否在播放。屬性是一個父組件分享給子組件的信息。

JSX中的屬性看起來和HTML屬性差不多。

我們給播放按鈕設置一個名為isMusicPlaying的屬性,它和this.state里的isMusicPlaying一樣。

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isMusicPlaying: false };
  }
handleClick() {
    if (this.state.isMusicPlaying) {
      this.setState({ isMusicPlaying: false });
    } else {
      this.setState({ isMusicPlaying: true });
    }
  };
render() {
    return (
      <div>
 **<PlayButton isMusicPlaying={this.state.isMusicPlaying} />**      </div>
    );
  }
}

當Container的狀態改變,PlayButton屬性也會改變,PlayButton函數也會被再次調用。這意味著我們的組件會在屏幕上更新。

在PlayButton里,我們可以對改變做出反應,因為PlayButton會將得到的屬性作為參數。

function PlayButton(**props**) {
 **const className = props.isMusicPlaying ? 'play active' : 'play';**  return <a href="#" title="Play video" />;
}

如果我們改變狀態為this.state = {isMusicPlaying:true };,然后刷新頁面,你應該能看到暫停按鈕。

關于React你應該了解的一切:開始構建前你所需的基礎知識

基于屬性的事件

你的屬性沒有必要必須為信息。它們可以是函數。

function PlayButton(props) {
  const className = props.isMusicPlaying ? 'play active' : 'play';
  return <a href="#" title="Play video" />;
}
class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isMusicPlaying: false };
  }
handleClick() {
    if (this.state.isMusicPlaying) {
      this.setState({ isMusicPlaying: false });
    } else {
      this.setState({ isMusicPlaying: true });
    }
  };
render() {
    return (
      <div>
        <PlayButton 
          **onClick={this.handleClick.bind(this)}** 
          isMusicPlaying={this.state.isMusicPlaying} 
        />
      </div>
    );
  }
}

現在,當我們點擊播放按鈕,Container的狀態會改變,這會改變播放按鈕的屬性,導致按鈕在頁面上刷新。

設置狀態的壞處

setState很糟糕,因為它不會立即響應。React會等待一會以便查看是否有更多改變要做,之后才會改變狀態。

這意味著你不確定當你調用setState時你的狀態會變成什么。

所以你不應該這樣做:

handleClick() {
  this.setState({ isMusicPlaying: !this.state.isMusicPlaying });
};

如果你是基于舊狀態來改變新狀態,你需要做點不一樣的工作。

你需要賦給getState一個函數而不是對象。這個函數獲得舊狀態作為一個參數,返回一個新對象,這個對象即為新狀態。

它看起來像是這樣:

handleClick() {
  this.setState(prevState => {
    return { 
      isMusicPlaying: !prevState.isMusicPlaying   
    };
  });
};

這更困難,但只有當你使用舊狀態來獲得新狀態時才需要。如果不是,你可以只賦給setState一個對象。

什么是Refs?

讓我們試試播放音樂。

First, we add an `` tag: 首先,我們添加一個標簽:

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isMusicPlaying: false };
  }
handleClick() {
    this.setState(prevState => {
      return { 
        isMusicPlaying: !prevState.isMusicPlaying   
      };
    });
  };
render() {
    return (
      <div>
        <PlayButton 
          onClick={this.handleClick.bind(this)} 
          isMusicPlaying={this.state.isMusicPlaying} 
        />
 **<audio />**      </div>
    );
  }
}

我們需要一種方法來獲得標簽,然后在該標簽上調用play()或者pause()。我們可以用document.getElementById('audio').play()實現,但還有更好的React方法。

我們賦給它一個屬性ref,該屬性和被作為第一個參數的元素一起被調用。它獲得這個元素并把元素分配給this.audio。

<audio> { this.audio = audioTag }}** />

Container每次進行渲染時都會調用這個函數,這意味著this.audio會始終保持更新。

我們這時可以播放和暫停音樂:

handleClick() {
  **if (this.state.isMusicPlaying) {
    this.audio.pause();
  } else {
    this.audio.play();
  }**
  this.setState(prevState => {
    return { 
      isMusicPlaying: !prevState.isMusicPlaying   
    };
  });
};

使用選擇文件按鈕上傳一個音樂文件(mp3文件更合適),然后點擊播放就能欣賞音樂啦。

跳出index.html

和你想的一樣,我們的React不應該圍著標簽轉。

React需要很多構建配置。幸運的是,一些工具比如 Create React App 為你做好了一切。

安裝該工具來創建你自己的React項目。跟著它們簡潔的文檔,開始編輯src目錄里的JavaScript代碼,把你所學到的React知識應用在這吧。

祝賀

現在你可以用React做一些東西了。

接下來,閱讀其他文章來獲得更多信息。一篇是 React best practices ,另一篇是關于React一個有用的部分 lifecycle methods .

如果你從本篇文章中學到了一點東西,請為我們點贊,并分享給你的朋友們。

來自:

 

 本文由用戶 wxl9521 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!