歡迎關注公衆號:n平方
若有問題或建議,請後臺留言,我會盡力解決你的問題。
當你以爲原生js代碼亂七八糟的時候,那就是要體驗一下React。(祕籍在最後)css
React 的核心思想是:封裝組件。
各個組件維護本身的狀態和 UI,當狀態變動,自動從新渲染整個組件。
React 大致包含下面這些概念:html
經驗:
前端框架的基本組成:
組件及其生命週期、樣式、路由、網絡請求、數據存儲和傳遞。前端
import React, { Component } from 'react'; import { render } from 'react-dom'; class HelloMessage extends Component { render() { return <div>Hello {this.props.name}</div>; } } // 加載組件到 DOM 元素 mountNode render(<HelloMessage name="John" />, mountNode);
解析:node
當組件狀態 state 有更改的時候,React 會自動調用組件的 render 方法從新渲染整個組件的 UI。
固然若是真的這樣大面積的操做 DOM,性能會是一個很大的問題,因此 React 實現了一個Virtual DOM,組件 DOM 結構就是映射到這個 Virtual DOM 上,React 在這個 Virtual DOM 上實現了一個 diff 算法,當要從新渲染組件的時候,會經過 diff 尋找到要變動的 DOM 節點,再把這個修改更新到瀏覽器實際的 DOM 節點上,因此實際上不是真的渲染整個 DOM 樹。這個 Virtual DOM 是一個純粹的 JS 數據結構,因此性能會比原生 DOM 快不少。react
「單向數據綁定」是 React 推崇的一種應用架構的方式。webpack
package.json看依賴git
{ "name": "learning-01", "version": "1.0.0", "description": "", "main": "webpack.config.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack-dev-server --config ./webpack.config.js --mode development --open", "build": "webpack" }, "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.3.3", "@babel/preset-env": "^7.3.1", "@babel/preset-react": "^7.0.0", "babel-loader": "^8.0.5", "clean-webpack-plugin": "^1.0.1", "html-webpack-plugin": "^3.2.0", "react-hot-loader": "^4.7.1", "webpack": "^4.29.5", "webpack-cli": "^3.2.3", "webpack-dev-server": "^3.2.0" }, "dependencies": { "react": "^16.8.3", "react-dom": "^16.8.3" } }
webpack.config.js看配置github
const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); module.exports = { entry: './src/index.js', output: { path: __dirname + '/dist', publicPath: '/', filename: 'bundle.js' }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ['babel-loader'] } ] }, resolve: { extensions: ['*', '.js', '.jsx'] }, plugins: [ new CleanWebpackPlugin(['dist']), new webpack.HotModuleReplacementPlugin(), new HtmlWebpackPlugin({template:'index.html'}) ], devServer: { contentBase: './dist', hot: true } };
基本搭建環境參考(可直接clone)
https://github.com/xbmchina/r...web
// Input (JSX): var person = <Person name={window.isLoggedIn ? window.name : ''} />; // Output (JS): var person = React.createElement( Person, {name: window.isLoggedIn ? window.name : ''} );
{/* child comment, put {} around */}
<div dangerouslySetInnerHTML={{__html: 'cc © 2015'}} />
var props = {}; props.foo = x; props.bar = y; var component = <Component {...props} />;
componentWillMount
只會在裝載以前調用一次,在 render 以前調用,你能夠在這個方法裏面調用 setState 改變狀態,而且不會致使額外調用一次 render算法
componentDidMount
只會在裝載完成以後調用一次,在 render 以後調用,從這裏開始能夠經過 ReactDOM.findDOMNode(this) 獲取到組件的 DOM 節點。
var React = require('react'); var ReactDOM = require('react-dom'); import ComponentHeader from './components/ComponentHeader'; import ComponentFooter from './components/ComponentFooter'; import BodyIndex from './components/BodyIndex'; import BasicExample from './root' export default class Index extends React.Component { constructor(props) { super(props); this.state = { count: props.initialCount }; } //組件即將加載 componentWillMount() { //定義你的邏輯便可 console.log("Index - componentWillMount"); } //組件加載完畢 componentDidMount() { console.log("Index - componentDidMount"); } render() { /* var component; if (用戶已登陸) { component = <ComponentLoginedHeader/> } else{ component = <ComponentHeader/> } */ return ( <div> <ComponentHeader /> <BodyIndex /> <ComponentFooter /> </div> ); } } ReactDOM.render(<BasicExample/>,document.getElementById('app'))
給事件處理函數傳遞額外參數的方式:bind(this, arg1, arg2, ...)
render: function() { return <p onClick={this.handleClick.bind(this, 'extra param')}>; }, handleClick: function(param, event) { // handle click }
Refs
另一種方式就是經過在要引用的 DOM 元素上面設置一個 ref 屬性指定一個名稱,而後經過 this.refs.name 來訪問對應的 DOM 元素。
好比有一種狀況是必須直接操做 DOM 來實現的,你但願一個 <input/> 元素在你清空它的值時 focus,你無法僅僅靠 state 來實現這個功能。
class App extends Component { constructor() { return { userInput: '' }; } handleChange(e) { this.setState({ userInput: e.target.value }); } clearAndFocusInput() { this.setState({ userInput: '' }, () => { this.refs.theInput.focus(); }); } render() { return ( <div> <div onClick={this.clearAndFocusInput.bind(this)}> Click to Focus and Reset </div> <input ref="theInput" value={this.state.userInput} onChange={this.handleChange.bind(this)} /> </div> ); } }
使用組件的目的就是經過構建模塊化的組件,相互組合組件最後組裝成一個複雜的應用。在 React 組件中要包含其餘組件做爲子組件,只須要把組件看成一個 DOM 元素引入就能夠了。
var React = require('react'); var ReactDOM = require('react-dom'); import ComponentHeader from './components/ComponentHeader'; import ComponentFooter from './components/ComponentFooter'; import BodyIndex from './components/BodyIndex'; class Index extends React.Component { //組件即將加載 componentWillMount() { //定義你的邏輯便可 console.log("Index - componentWillMount"); } //組件加載完畢 componentDidMount() { console.log("Index - componentDidMount"); } render() { /* var component; if (用戶已登陸) { component = <ComponentLoginedHeader/> } else{ component = <ComponentHeader/> } */ return ( <div> <ComponentHeader /> <BodyIndex /> <ComponentFooter /> </div> ); } } ReactDOM.render( <Index />, document.getElementById('app'));
父子組件間通訊
就是經過 props 屬性傳遞,在父組件給子組件設置 props,而後子組件就能夠經過 props 訪問到父組件的數據/方法,這樣就搭建起了父子組件間通訊的橋樑。
非父子組件間的通訊
使用全局事件 Pub/Sub 模式,在 componentDidMount 裏面訂閱事件,在 componentWillUnmount 裏面取消訂閱,當收到事件觸發的時候調用 setState 更新 UI。
通常來講,對於比較複雜的應用,推薦使用相似 Flux 這種單項數據流架構
1.內聯樣式
在render函數裏定義
const styleComponentHeader = { header: { backgroundColor: '#333333', color: '#FFFFFF', 'padding-top': '12px', 'paddingBottom: '16px' } };
注意樣式的駝峯寫法 style = {styleComponentHeader.header}
文件中引用css的樣式 注意class須要更改爲className肯定是動畫、僞類(hover)等不能使用
2.內聯樣式中的表達式
paddingBottom:(this.state.minHeader)?"3px":"15px"
注意好好理解這裏的state引發樣式的即時變化
3.CSS模塊化
緣由:避免全局污染、命名混亂、依賴管理不完全、沒法共享變量、代碼壓縮不完全
npm install --save-dev style-loader css-loader npm install --save-dev babel-plugin-react-html-attrs //爲了使用原生的html屬性名
全局樣式和局部樣式
:local(.normal){color:green;} //局部樣式 :global(.btn){color:red;} //全局樣式
CSS模塊化的優勢 全部樣式都是local的,解決了命名衝突和全局污染問題 class名生成規則配置靈活,能夠此來壓縮class名 只需引用組件的JS就能搞定組件全部的js和css 依然是css,幾乎零學習成本
jsx樣式與css的互轉 工具:https://staxmanade.com/CssToReact/
官網:https://reacttraining.com/rea...
GitHub:https://github.com/ReactTrain...
注意點:
1.引用的包是有區別的。
2.控制頁面的層級關係 單頁面構建Router控制
底層機制 React: state/props -> Components ->UI Router: location ->Router -> UI
3.router傳參
定義: path="list/:id" 使用: this.props.match.params.id
4.地址沒法刷新(巨坑)
表現:'/' 根節點 Home 顯示無誤,不過其餘任何路由 例如 /detail,均顯示 Cannot GET /detail。
解決方法:
module.exports = { // 省略其餘的配置 devServer: { historyApiFallback: true } }
詳情能夠參考:https://blog.csdn.net/zwkkkk1...
官網:https://github.com/github/fetch
fetch('/users.json') .then(function(response) { return response.json() }).then(function(json) { console.log('parsed json', json) }).catch(function(ex) { console.log('parsing failed', ex) })
下期再講
練習代碼
學習Demo樣例:https://github.com/xbmchina/r...
項目Demo樣例:https://github.com/xbmchina/r...
React相關資料
**React官網:https://reactjs.org/docs/hell...
React中文網:https://react.docschina.org/
React學習文檔:http://caibaojian.com/react/
webpack搭建React:https://segmentfault.com/a/11...
React-router官網:https://reacttraining.com/rea...
阿里UI庫Ant Design:https://ant.design/index-cn
阿里圖標庫:https://www.iconfont.cn/
谷歌的ReactUI庫:https://material-ui.com/
css轉React:https://staxmanade.com/CssToR...
Fetch請求:https://github.com/github/fetch**
本人水平有限,歡迎各位建議以及指正。順便關注一下公衆號唄,會常常更新文章的哦。