入門學(xué)習(xí) React 一些實(shí)例

這是幾個(gè)入門學(xué)習(xí) React 的小 Demo,幫助自己學(xué)習(xí)了解 React 的運(yùn)行機(jī)制,結(jié)合 React官方文檔,會(huì)更佳噢...

DEMO 目錄

  1. ReactDOM.render()
  2. Use Array in JSX
  3. 組件
  4. this.props.children
  5. PropTypes
  6. 獲取真實(shí)的 DOM 節(jié)點(diǎn)
  7. this.state
  8. 表單
  9. 組件的生命周期
  10. 使用 Promise 獲取 Github 的數(shù)據(jù)
  11. Todo List
  12. 井字棋(Tic Tac Toe)

引入資源

<div id="output"></div>
<!-- Load Babel -->
<!-- v6 <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Your custom script here -->
<script type="text/babel">
const getMessage = () => "Hello World";
document.getElementById('output').innerHTML = getMessage();
</script>

Demo01: ReactDOM.render()

Demo / Source

初始化咱先 Hello 一下,使用 jsx 語(yǔ)法,碰到代碼塊使用({ })包起來(lái),碰到 html 標(biāo)簽,就使用(< />):

var names = ["AAA", "BBB", "CCC"];
ReactDOM.render(
  <div>
    {names.map(function(name) {
      return <h2>Hello, {name}!</h2>;
    })}
  </div>,
  document.getElementById("example")
);

Demo02: Use Array in JSX

Demo / Source

如果 JavaScript 的變量是個(gè)數(shù)組,會(huì)展開(kāi)這個(gè)數(shù)組的所有項(xiàng).

var arr = [<h1 key="h1">Hello,</h1>, <h2 key="h2">React is awesome!</h2>];
ReactDOM.render(<div>{arr}</div>, document.getElementById("example"));

Demo03: 組件

Demo / Source

變量 HelloMsg 是一個(gè)組件類。模板插入 <HelloMsg /> 時(shí),會(huì)自動(dòng)生成 HelloMsg 的一個(gè)實(shí)例。所有組件類都必須有自己的 render 方法,用于輸出組件。

class HelloMsg extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
ReactDOM.render(
  <HelloMsg name="Dataozi" />,
  document.getElementById("example")
);

Demo04: this.props.children

Demo / Source

this.props 對(duì)象的屬性與組件的屬性一一對(duì)應(yīng),但是有一個(gè)例外,就是 this.props.children 屬性。

ps: 注意大小寫(xiě) React.Children、React.Component

class NotesList extends React.Component {
  render() {
    return (
      <ol>
        {React.Children.map(this.props.children, function(child) {
          return <li>{child}</li>;
        })}
      </ol>
    );
  }
}
ReactDOM.render(
  <NotesList>
    <span>Hello</span>
    <span>World</span>
    <span>React</span>
  </NotesList>,
  document.getElementById("example")
);

Demo05: PropTypes

Demo / Source

React 內(nèi)置了一些類型檢查的功能。要在組件的 props 上進(jìn)行類型檢查,你只需配置特定的 propTypes 屬性:

var data = {
  tilte: "Hello",
  age: 19,
  isStudent: true
};
class MyTitle extends React.Component {
  static propTypes = {
    tilte: PropTypes.string,
    age: PropTypes.number,
    isStudent: PropTypes.bool
  };
  render() {
    return (
      <div>
        <h1>{this.props.data.tilte}</h1>
        <h2>{this.props.data.age}</h2>
        <h3>{this.props.data.isStudent ? "Yes" : "No"}</h3>
      </div>
    );
  }
}
ReactDOM.render(<MyTitle data={data} />, document.getElementById("root"));

還可以通過(guò)配置特定的 defaultProps 屬性來(lái)定義 props 的默認(rèn)值:

class DefaultTitle extends React.Component {
  render() {
    return <h4>{this.props.title}</h4>;
  }
}
//指定 props 的默認(rèn)值:
DefaultTitle.defaultProps = {
  title: "Hello React!"
};

ReactDOM.render(<DefaultTitle />, document.getElementById("root2"));

Demo06: 獲取真實(shí)的 DOM 節(jié)點(diǎn)

Demo / Source

Refs 提供了一種方式,允許我們?cè)L問(wèn) DOM 節(jié)點(diǎn)或在 render 方法中創(chuàng)建的 React 元素。

  • 創(chuàng)建 Refs: Refs 是由React.createRef()創(chuàng)建的,并通過(guò) ref 屬性附加到 React 元素(比如 input)
  • 訪問(wèn) Refs: 當(dāng) ref 被傳遞給 render 中的元素時(shí),對(duì)該節(jié)點(diǎn)的引用可以在 ref 的 current 屬性中被訪問(wèn),this.myTextFocus.current.focus();

你不能在函數(shù)組件上使用 ref 屬性,因?yàn)樗鼈儧](méi)有實(shí)例

組件 MyComponent 的子節(jié)點(diǎn)有一個(gè)文本輸入框,用于獲取用戶的輸入。這時(shí)就必須獲取真實(shí)的 DOM 節(jié)點(diǎn),虛擬 DOM 是拿不到用戶輸入的。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // 創(chuàng)建一個(gè) ref 來(lái)存儲(chǔ) myTextFocus 的 DOM 元素
    this.myTextFocus = React.createRef();
    this.handerClick = this.handerClick.bind(this);
  }
  handerClick() {
    // 直接使用原生 API 使 text 輸入框獲得焦點(diǎn)
    // 通過(guò) "current" 來(lái)訪問(wèn) DOM 節(jié)點(diǎn)
    this.myTextFocus.current.focus();
  }
  render() {
    // 告訴 React 我們想把 <input> ref 關(guān)聯(lián)到
    // 構(gòu)造器里創(chuàng)建的 `myTextFocus` 上
    return (
      <div>
        <input type="text" ref={this.myTextFocus} />
        <input type="button" value="點(diǎn)擊聚焦" onClick={this.handerClick} />
      </div>
    );
  }
}
ReactDOM.render(<MyComponent />, document.getElementById("root"));

Demo07: this.state

Demo / Source

學(xué)習(xí)如何封裝真正可復(fù)用的 Clock 組件。它將設(shè)置自己的計(jì)時(shí)器并每秒更新一次。

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() }; //為 this.state 賦初值
  }

  componentDidMount() {
    // Clock初次被渲染到DOM時(shí),為?其掛載一個(gè)計(jì)時(shí)器
    this.timerID = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    // Clock被刪除時(shí),卸載其計(jì)時(shí)器
    clearInterval(this.timerID);
  }

  tick() {
    // 使用 this.setState() 來(lái)時(shí)刻更新組件 state
    this.setState({ date: new Date() });
  }

  render() {
    return (
      <div>
        <h1>Hello, React!</h1>
        <h2>現(xiàn)在是北京時(shí)間:{this.state.date.toLocaleTimeString()}</h2>
      </div>
    );
  }
}

ReactDOM.render(<Clock />, document.getElementById("root"));

Demo08: 表單

Demo / Source

受控組件:渲染表單的 React 組件還控制著用戶輸入過(guò)程中表單發(fā)生的操作,被 React 以這種方式控制取值的表單輸入元素就叫做“受控組件”。

即:表單數(shù)據(jù)是由 React 組件來(lái)管理的。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // 唯一數(shù)據(jù)源
      value: ""
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleChange(event) {
    this.setState({
      value: event.target.value // 顯示的值將隨著用戶輸入而更新
    });
  }
  handleSubmit(event) {
    if (this.state.value) {
      alert("接受到的name值是:" + this.state.value);
    }
    event.preventDefault();
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          value={this.state.value}
          onChange={this.handleChange}
        />
        <input type="submit" value="提交" />
      </form>
    );
  }
}

ReactDOM.render(<NameForm />, document.getElementById("root"));

非受控組件:表單數(shù)據(jù)將交由 DOM 節(jié)點(diǎn)來(lái)處理,即使用 ref 來(lái)從 DOM 節(jié)點(diǎn)中獲取表單數(shù)據(jù)

Demo / Source

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.input = React.createRef();
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {
    alert("接受到的name值是:" + this.input.current.value);
    event.preventDefault();
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="text" ref={this.input} />
        <input type="submit" value="提交" />
      </form>
    );
  }
}

ReactDOM.render(<NameForm />, document.getElementById("root"));

Demo09: 組件的生命周期

Demo / Source

主要路線順序:掛載 - 更新 - 卸載 - 錯(cuò)誤處理

掛載

當(dāng)組件實(shí)例被創(chuàng)建并插入 DOM 中時(shí),其生命周期調(diào)用如下:

  • consctructor() --- React 組件的構(gòu)造函數(shù),不初始化 state 或不進(jìn)行方法綁定,則不需要
  • static getDerivedStateFromProps() --- 不常用
  • render() --- 唯一必須實(shí)現(xiàn)的方法,并且應(yīng)該是純函數(shù)
  • componentDidMount() --- 依賴于 DOM 節(jié)點(diǎn)的初始化應(yīng)該在這里

更新

當(dāng)組件的 props 或 state 發(fā)生變化時(shí),會(huì)觸發(fā)更新:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate() --- 不常用
  • componentDidUpdate() --- 在更新后會(huì)被立即調(diào)用

卸載

當(dāng)組件從 DOM 中移除時(shí):

  • componentWillUnmount() --- 會(huì)在組件卸載及銷毀之前直接調(diào)用

錯(cuò)誤處理

當(dāng)渲染過(guò)程,生命周期,或子組件的構(gòu)造函數(shù)中拋出錯(cuò)誤時(shí):

  • static getDerivedStateFromError()
  • componentDidCatch()

過(guò)期的生命周期方法:

  • UNSAFE_componentWillMount() --- 掛載前調(diào)用,目前使用 constructor()初始化 state
  • UNSAFE_componentWillReceiveProps()
  • UNSAFE_componentWillUpdate()
class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      fontSize: 12,
      opacity: 0.01
    };
  }
  componentDidMount() {
    this.timerID = setInterval(() => {
      let opacity = this.state.opacity;
      let fontSize = this.state.fontSize;
      opacity += 0.02;
      fontSize += 1;
      if (opacity >= 1) {
        opacity = 0.01;
      }
      if (fontSize >= 63) {
        fontSize = 12;
      }
      this.setState({
        fontSize,
        opacity
      });
    }, 100);
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  render() {
    return (
      <h1
        style={{ opacity: this.state.opacity, fontSize: this.state.fontSize }}
      >
        Hello, {this.props.name}
      </h1>
    );
  }
}
ReactDOM.render(<Hello name="React" />, document.getElementById("root"));

Demo10: 使用 Promise 獲取 Github 的數(shù)據(jù)

Demo / Source

ReactDOM.render(
  <ReportList
    promise={$.getJSON(
      "https://api.github.com/search/repositories?q=javascript&sort=stars"
    )}
  />,
  document.getElementById("root")
);

從 Github 的 API 抓取數(shù)據(jù),然后將 Promise 對(duì)象作為屬性,傳給 ReportList 組件。

如果 Promise 對(duì)象正在抓取數(shù)據(jù)(pending 狀態(tài)),組件顯示"loading...";

如果 Promise 對(duì)象報(bào)錯(cuò)(rejected 狀態(tài)),組件顯示報(bào)錯(cuò)信息;

如果 Promise 對(duì)象抓取數(shù)據(jù)成功(fulfilled 狀態(tài)),組件顯示獲取的數(shù)據(jù)。

在這里查看完整 Demo/源碼 --- 谷歌瀏覽器有時(shí)候會(huì)報(bào)跨域的問(wèn)題,可以使用火狐等瀏覽器試看

接下來(lái)來(lái)幾個(gè)混合實(shí)戰(zhàn)吧

Demo11: Todo List

Demo / Source

主要練習(xí)使用 propsstate,使用 state 保存現(xiàn)有的待辦事項(xiàng)列表及用戶的一些操作(刪除、完成)等。

class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: []
    };
    this.addItem = this.addItem.bind(this);
    this.deleteItem = this.deleteItem.bind(this);
    this.doneItem = this.doneItem.bind(this);
  }

  addItem(item) {
    const newItem = {
      text: item.text,
      id: Date.now(),
      done: false
    };
    this.setState({
      items: this.state.items.concat(newItem)
    });
  }

  deleteItem(index) {
    this.state.items.splice(index, 1);
    this.setState({
      items: this.state.items
    });
  }

  doneItem(index) {
    const items = this.state.items;
    const todo = items[index];
    items.splice(index, 1);
    todo.done = !todo.done;
    todo.done ? items.unshift(todo) : items.push(todo);
    this.setState({ items });
  }

  render() {
    return (
      <div className="container">
        <h1>TODO</h1>
        <TodoList
          items={this.state.items}
          deleteClick={this.deleteItem}
          doneClick={this.doneItem}
        />
        <TodoForm addItem={this.addItem} items={this.state.items} />
      </div>
    );
  }
}

Demo12: 井字棋(Tic Tac Toe)

Demo / Source

tic-tac-toe(三連棋)游戲的功能

  • [x] 能夠判定玩家何時(shí)獲勝
  • [x] 能夠記錄游戲進(jìn)程
  • [x] 允許玩家查看游戲的歷史記錄,也可以查看任意一個(gè)歷史版本的游戲棋盤狀態(tài)
  • [x] 在游戲歷史記錄列表顯示每一步棋的坐標(biāo),格式為 (列號(hào), 行號(hào))
  • [x] 在歷史記錄列表中加粗顯示當(dāng)前選擇的項(xiàng)目
  • [ ] 使用兩個(gè)循環(huán)來(lái)渲染出棋盤的格子,而不是在代碼里寫(xiě)死(hardcode)
  • [ ] 添加一個(gè)可以升序或降序顯示歷史記錄的按鈕
  • [ ] 每當(dāng)有人獲勝時(shí),高亮顯示連成一線的 3 顆棋子
  • [x] 當(dāng)無(wú)人獲勝時(shí),顯示一個(gè)平局的消息

學(xué)習(xí)資料

Github地址:戳我

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 現(xiàn)在最熱門的前端框架,毫無(wú)疑問(wèn)是 React 。上周,基于 React 的 React Native 發(fā)布,結(jié)果一...
    sakura_L閱讀 489評(píng)論 0 0
  • 現(xiàn)在最熱門的前端框架,毫無(wú)疑問(wèn)是React。在基于React的React Native發(fā)布一天之內(nèi),就獲得了 50...
    Mycro閱讀 1,126評(píng)論 3 6
  • 作者:阮一峰原文地址:http://www.ruanyifeng.com/blog/2015/03/react.h...
    IT程序獅閱讀 1,152評(píng)論 0 16
  • 3. JSX JSX是對(duì)JavaScript語(yǔ)言的一個(gè)擴(kuò)展語(yǔ)法, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,979評(píng)論 0 24
  • React基礎(chǔ) React組件化編程 Create React App 創(chuàng)建React 前端工程 題外話題:頁(yè)面性...
    BeautifulHao閱讀 1,641評(píng)論 0 3

友情鏈接更多精彩內(nèi)容