react方法返回html_React全家桶之React基础(推荐新手必看)
學(xué)習(xí)目標(biāo)
- 安裝create-react-app腳手架
- 熟練React基礎(chǔ)語法
- 掌握J(rèn)SX語法
- 掌握setState
- 掌握React生命周期
- 掌握props傳遞參數(shù)
- 掌握React組件通信
資源
- react
- create-react-app
起步
上手
- npm i -g create-react-app 安裝官方腳手架
- create-react-app 01_react 初始化
- react的api比較少,基本學(xué)習(xí)一次,就再也不用再看文檔,它的核心是JS
React&ReactDOM
React只做邏輯層,reactDOM去渲染真實(shí)的DOM
刪除src下面所有代碼,新建index.js
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App' ReactDOM.render(<App />,document.querySelector('#root'))新建 App.js
import React from 'react' class App extends React.Component {render() {return (<div>hello,小馬哥</div>)} } export default App;以上代碼感覺都沒有問題,但是發(fā)現(xiàn)了一個很有趣的標(biāo)簽語法,它既不是字符串也不是HTML
它被稱為JSX,是一個JavaScript的語法擴(kuò)展.我們建議在 React 中配合使用 JSX,JSX 可以很好地描述 UI 應(yīng)該呈現(xiàn)出它應(yīng)有交互的本質(zhì)形式。JSX 可能會使人聯(lián)想到模版語言,但它具有 JavaScript 的全部功能。
JSX
在JavaScript中直接寫的標(biāo)簽,是一個JSX(JS+XML,由于HTML也是XML的一種,可以認(rèn)為JS+HTML)元素,也是一個react元素,這個元素實(shí)際是一個對象,就是虛擬DOM元素
React 認(rèn)為渲染邏輯本質(zhì)上與其他 UI 邏輯內(nèi)在耦合.比如,在 UI 中需要綁定處理事件、在某些時(shí)刻狀態(tài)發(fā)生變化時(shí)需要通知到 UI,以及需要在 UI 中展示準(zhǔn)備好的數(shù)據(jù)。
import React, { Component } from 'react'import logo from './favicon.ico' const ele = <h2>hello,world</h2> function formatName(user) {// 也可以是個表達(dá)式return user.firstName + '' + user.lastName; } const user = {firstName: '張',lastName: '三豐' }//jsx也可以是表達(dá)式 function getGreeting(user) {if (user) {return <h1>hello {formatName(user)}</h1>}return <h1>hello,小馬哥</h1> } export default class App extends Component {render() {return (<div>{ele}{/* jsx運(yùn)算 */}{2 + 1}<br />{/*jsx嵌入表達(dá)式*/}{formatName(user)}{/* 添加屬性 */}<img src={logo} alt="" /></div>// getGreeting())} }強(qiáng)烈建議大家閱讀官網(wǎng),針對React.render()內(nèi)部的實(shí)現(xiàn)操作
元素渲染
元素是構(gòu)成React應(yīng)用的最小磚塊,比如:const ele = <h1>hello,world</h1>與瀏覽器的 DOM 元素不同,React 元素是創(chuàng)建開銷極小的普通對象。React DOM 會負(fù)責(zé)更新 DOM 來與 React 元素保持一致
上節(jié)課的ReactDOM.render()其實(shí)就是在渲染DOM節(jié)點(diǎn)
更新已渲染的元素
React元素是不可變對象,一旦被創(chuàng)建,無妨更改它的子元素或者屬性
計(jì)時(shí)器的例子
function tick() {const element = (<div><h1>Hello, world!</h1><h2>{new Date().toLocaleTimeString()}.</h2></div>);ReactDOM.render(element, document.querySelector('#root')); }setInterval(tick, 1000);大多數(shù)情況下,React應(yīng)用只會調(diào)用一次ReactDOM.render()
React只需要更新它需要更新的部分
React DOM會將元素和它的子元素與它們之前的狀態(tài)進(jìn)行比較,并只會進(jìn)行必要的更新來使DOM達(dá)到預(yù)期的狀態(tài)
循環(huán)綁定元素
當(dāng)數(shù)據(jù)從后端請求回來之后,在React中,一般都需要循環(huán)綁定元素
map綁定
在React中,循環(huán)綁定元素都是使用map方法,不能使用forEach是因?yàn)閒orEach沒有返回值
let ul = (<ul>{ arr.map((item, index)=>{return <li key={index}>{item}</li>}) } </ul>);結(jié)果會是一個 JSX 元素組成的數(shù)組,放入頁面中,不會使用逗號分隔開。
循環(huán)綁定的 JSX 元素,必須要有 key 屬性,來區(qū)分不同的元素,否則會報(bào)錯。過濾元素
同樣通過map方法,只要把不符合條件的元素,返回為null即可,原因在于,null會被表示為空.如果使用filter,那么就沒有辦法對元素進(jìn)行處理,只能過濾,還是需要使用map進(jìn)行處理
let ul = (<ul>{ arr.map((item, index)=>{return (item.price < 1000 ? null : <li key={index}>{item}</li>;)}) } </ul>)ref和refs
在React中,類似于Vue,可以通過ref標(biāo)記元素,然后通過this.refs獲取元素,只是Vue中使用的是this.$refs獲取元素
字符串寫法
通過設(shè)置一個字符串值來標(biāo)記元素,然后通過這個字符串作為屬性獲取元素
class Input extends Component {handleChange = (e) => {console.log(this.refs.a.value)}render() {return (<div><input type="text" ref="a" onChange={this.handleChange} /></div>)} }函數(shù)寫法
函數(shù)作為一個ref的屬性值,這個函數(shù)接受一個參數(shù),就是真實(shí)的DOM元素
可以把這個元素掛載到實(shí)例上,方便后面的操作
class Input extends React.Component {componentDidMount() {console.log(this.a); //獲取真實(shí)的DOM元素}render() {return (<div><input type="text" ref={x=>this.a = x}/> </div>);} }組件&props
React創(chuàng)建組件有來兩種方式
- 函數(shù)聲明
- 類聲明
React組件特點(diǎn):
- 組件名稱應(yīng)該首字母大寫,否則會報(bào)錯
- 組件定義之后,可以像JSX元素一樣使用
- 必須使用render函數(shù)才能將虛擬DOM渲染成真實(shí)的DOM
- 使用組件時(shí),可以使用單標(biāo)簽,也可以使用雙標(biāo)簽
函數(shù)組件
組件,從概念上類似于 JavaScript 函數(shù)。它接受任意的入?yún)?#xff08;即 “props”),并返回用于描述頁面展示內(nèi)容的 React 元素。
- 函數(shù)聲明的組件,必須返回一個JSX元素
- 可以通過屬性給組件傳遞值,函數(shù)通過props參數(shù)屬接收
定義組件最簡單的方式就是編寫JavaScript函數(shù)
function Welcome(props){return <h2>hello,{props.name}</h2> }我們稱為該組件為"函數(shù)組件",因?yàn)樗举|(zhì)上就是一個函數(shù)
類聲明組件
使用ES6的class的方式定義組件
類聲明組件需要注意
- 在React中有一個屬性Component,是一個基類,使用類聲明組件時(shí),必須繼承這個基類
- 在類中,必須有render函數(shù),constructor不是必須的
- 在render函數(shù)中**,需要return一個JSX元素**
例如,<div />代表HTML的div標(biāo)簽,而<Welcome />則代表一個組件,并且需在作用域內(nèi)使用Welcome
兩種方式的區(qū)別
真實(shí)項(xiàng)目中,都只使用class定義組件
- class定義的組件中有this,狀態(tài),生命周期
- function聲明都沒有
組合組件
組件可以輸出的時(shí)候嵌入其他的組件。這就可以讓我們用同一組件中來抽離出任意層次的細(xì)節(jié)(復(fù)用組件)。按鈕,表單,對話框,甚至整個屏幕的內(nèi)容:在 React 應(yīng)用程序中,這些通常都會以組件的形式表示。
什么是復(fù)合組件:
- 將多個組件進(jìn)行組合,例如調(diào)用兩次相同的組件
- 結(jié)構(gòu)非常復(fù)雜時(shí)需要將組件拆分成小組件
- 會存在父子關(guān)系的數(shù)據(jù)傳遞
可想而知,React開發(fā)其實(shí)就是組件化開發(fā),因?yàn)镽eact真的是組件化開發(fā)的鼻祖
提取組件
將組件拆分成更小的組件
import React, { Component } from 'react'; import ReactDOM from 'react-dom';// 所有props是只讀的,不能直接修改 class Avatar extends Component {render() {return (<img src={this.props.user.avatarUrl} alt={this.props.user.name} />);} }class UserInfo extends Component {constructor(props) {super(props);console.log(this.props);}render() {return (<div className="userinfo"><Avatar user={this.props.user}></Avatar><div className='username'><h3>{this.props.user.name}</h3></div></div>);} }class Comment extends Component {constructor(props) {super(props);}render() {return (<div className='comment'><UserInfo user={this.props.user}></UserInfo><div className="Comment-text">{this.props.user.text}</div><div className="Comment-date">{this.props.user.date}</div></div>);} } class App extends Component {constructor() {super();this.user = {avatarUrl: 'https://hcdn1.apeland.cn/media/course/icon2.png',name: '張三',text: "hello,React component",date: new Date().toLocaleString()}}render() {return (<div><Comment user={this.user}></Comment></div>)} } // 組合組件 ReactDOM.render(<App></App>,document.querySelector('#root'));最初看上去,提取組件可能是一件繁重的工作,但是,在大型應(yīng)用中,構(gòu)建可復(fù)用組件庫是完全值得的。 根據(jù)經(jīng)驗(yàn)來看,如果 UI 中有一部分被多次使用(Button,Panel,Avatar),或者組件本身就足夠復(fù)雜(App,Comment),那么它就是一個可復(fù)用組件的候選項(xiàng)。你說對吧!
父子組件通信
父傳子
父組件通過行間屬性傳遞數(shù)據(jù)到子組件,子組件通過實(shí)例上的props屬性接收新的數(shù)據(jù)
React 的數(shù)據(jù)是單向數(shù)據(jù)流,只能一層一層往下傳遞。當(dāng)組件的屬性發(fā)生改變,那么當(dāng)前的視圖就會更新
子傳父
通過給子組件傳遞一個函數(shù),子組件調(diào)用父親的函數(shù)將值作為參數(shù)傳遞給父組件,父組件更新值,刷新視圖。
父組件中定義一個函數(shù),通過屬性傳遞給子組件。
這個傳遞的函數(shù)必須是一個箭頭函數(shù)import React, { Component } from 'react'; import ReactDOM from 'react-dom';class ChildCom extends Component {constructor(props) {super(props);console.log(props);this.state = {val:''}this.handlerClick = this.handlerClick.bind(this);this.handlerChange = this.handlerChange.bind(this);}handlerChange(event){this.setState({val: event.target.value})}handlerClick(){if(this.state.val){this.props.addHandler(this.state.val);// 清空輸入框this.setState({val: ''})}}render() {return (<div><input type="text" value = {this.state.val} onChange = {this.handlerChange}/><button onClick={this.handlerClick}>添加</button>{this.props.menus.map((item,index) => {return <p key = {index}>{item}</p>})}</div>);} }class App extends Component {constructor(props) {super(props);this.state = {menus: ['烤腰子', '辣炒雞丁', '炸黃花魚']}}// 一定要使用箭頭函數(shù)addHandler = (val)=>{this.state.menus.push(val);this.setState({menus:this.state.menus})}render() {// 修改狀態(tài)之后,會重新調(diào)用renderreturn (<div><ChildCom menus={this.state.menus} addHandler = {this.addHandler}></ChildCom></div>);} }ReactDOM.render(<App />, document.querySelector('#root'));Props的只讀性
組件無論是使用函數(shù)聲明還是通過 class 聲明,都決不能修改自身的 props
//該函數(shù)不會嘗試更改入?yún)?#xff0c;且多次調(diào)用下相同的入?yún)⑹冀K返回相同的結(jié)果。 function sum(a, b) {return a + b; } //它更改了自己的入?yún)?function withdraw(account, amount) {account.total -= amount; }所有 React 組件都必須像純函數(shù)一樣保護(hù)它們的 props 不被更改。
state
組件狀態(tài)
組件中數(shù)據(jù)的來源
- 屬性:是由外接傳遞過來的
- 狀態(tài):是自己的,只能通過setState來改變狀態(tài)
修改狀態(tài)
除了constructor之外的其它地方,如果需要修改狀態(tài),都只能通過this.setState方法
這個方法傳入的第一個參數(shù),可以是一個對象,也可以是一個函數(shù)
- 是一個對象,這個對象中包含需要改變的屬性,它會與原有的狀態(tài)進(jìn)行合并
- 是一個函數(shù),接收第一個參數(shù)是 prevState,上一個狀態(tài)對象,第二個參數(shù)是 props
這個方法的第二個參數(shù),是一個回調(diào)函數(shù),在狀態(tài)改變之后執(zhí)行。
如果下一個狀態(tài)依賴于上一個狀態(tài),需要寫成函數(shù)的方式
關(guān)于setState
- 在 react 組件的生命周期或事件的綁定中,setState 是異步的
- 在定時(shí)器或原生的事件中,setState 不一定是異步的
在元素渲染章節(jié)中,我們只了解了一種更新 UI 界面的方法。通過調(diào)用 ReactDOM.render() 來修改我們想要渲染的元素
function tick() {const element = (<div><h1>Hello, world!</h1><h2>{new Date().toLocaleTimeString()}.</h2></div>);ReactDOM.render(element, document.querySelector('#root')); }setInterval(tick, 1000);本節(jié)學(xué)習(xí)如何封裝真正可復(fù)用的Clock組件
import React, { Component } from 'react'; import ReactDOM from 'react-dom';// 學(xué)習(xí)如何封裝真正可復(fù)用的Clock組件。 class Clock extends Component {constructor(props) {super(props);this.state = {date: new Date().toLocaleString()}}componentDidMount() {this.timer = setInterval(() => {// 注意1 不能直接修改state// this.state.date = new Date(); //錯誤// 注意2: setState()是異步的this.setState({date: new Date().toLocaleString()})}, 1000);}componentWillUnmount() {clearInterval(this.timer);}render() {// 修改狀態(tài)之后,會重新調(diào)用renderreturn (<div><h3>當(dāng)前時(shí)間為:{this.state.date}</h3></div>);} }ReactDOM.render(<Clock />, document.querySelector('#root'));生命周期
當(dāng)然react16.x之后,又更新了新的生命周期方法。如圖,React生命周期主要包括三個階段:初始化階段、運(yùn)行中階段和銷毀階段,在React不同的生命周期里,會依次觸發(fā)不同的鉤子函數(shù),下面我們就來詳細(xì)介紹一下React的生命周期函數(shù)import React, { Component } from 'react'; import ReactDOM from 'react-dom';class SubCounter extends Component {// 組件將要接收屬性componentWillReceiveProps(newProps){console.log('9.子組件將要接收到新屬性',newProps);}shouldComponentUpdate(newProps,newState){console.log('10.子組件是否需要更新')if(newProps.num % 3 === 0){return true;}else{return false;}}componentWillUpdate() {console.log('11、子組件將要更新');}componentDidUpdate() {console.log('13、子組件更新完成');}componentWillUnmount() {console.log('14、子組件將卸載');}render() {console.log('12.子組件掛載中')return (<div><p>{this.props.num}</p> </div>);} }class Counter extends Component {static defaultyProps = {//1.加載默認(rèn)屬性name:'小馬哥',age:18}constructor(props) {super(props);//2.記載默認(rèn)狀態(tài)this.state = {num: 0}}componentWillMount() {// 此時(shí)可以訪問屬性和狀態(tài),可以進(jìn)行api調(diào)用,但沒辦法做DOM相關(guān)操作console.log('3.父組件將要被掛載');}componentDidMount() {// 組件已掛載,可進(jìn)行狀態(tài)更新操作。通常 都在此方法中發(fā)送請求console.log('5.組件掛載完成');}shouldComponentUpdate(newProps, newState) {// 組件是否需要更新,返回布爾值,優(yōu)化點(diǎn)console.log('6.父組件是否被更新');// console.log(newProps, newState);if (newState.num % 2 === 0) {return true;} else {// 此函數(shù) 會返回一個boolean值,返回true更新頁面,返回false不更新頁面return false;}}componentWillUpdate(){console.log('7.父組件將要更新');}componentDidUpdate(){console.log('8.父組件更新完成');}handlerClick = () => {// 可能,只是說可能,官網(wǎng)上都是這樣說的.......會導(dǎo)致計(jì)數(shù)可能不準(zhǔn)確,// this.setState({// num: parseInt(this.props.increment) + this.state.num// })// 發(fā)現(xiàn)點(diǎn)擊之后,得到的結(jié)果為0,這是因?yàn)閟etState()是異步的// console.log(this.state.num);// 要解決這個問題,可以讓 setState() 接收一個函數(shù)而不是一個對象。// 這個函數(shù)用上一個 state 作為第一個參數(shù),將此次更新被應(yīng)用時(shí)的 props 做為第二個參數(shù)this.setState((state, props) => {return {num: state.num + parseInt(props.increment)}}, () => {console.log(this.state.num);})}render() {// 修改狀態(tài)之后,會重新調(diào)用renderconsole.log('4.render(父組件)渲染了');return (<div><h3>當(dāng)前數(shù)值:{this.state.num}</h3><button onClick={this.handlerClick}>+1</button><h3>我是子組件</h3><SubCounter num = {this.state.num}></SubCounter></div>);} }ReactDOM.render(<Counter increment='1' />, document.querySelector('#root'));
受控組件
受控組件,就是受狀態(tài)控制的組件,需要與狀態(tài)進(jìn)行相應(yīng)的綁定
- 受控組件必須要有一個 onChange 事件,否則不能使用
- 受控組件可以賦予默認(rèn)值(實(shí)際上就是設(shè)置初始狀態(tài))
- 官方推薦使用受控組件的寫法
可以使用受控組件實(shí)現(xiàn)雙向綁定。
非受控組件,則不是通過與狀態(tài)進(jìn)行綁定來實(shí)現(xiàn)的,而是通過操作 DOM 來實(shí)現(xiàn)。除非操作 DOM,否則沒有辦法設(shè)置默認(rèn)值。
受控組件實(shí)現(xiàn)
- 設(shè)置初始狀態(tài),也就是設(shè)置默認(rèn)值
- 將輸入框的 value`` 值與相應(yīng)狀態(tài)進(jìn)行綁定
- 使用 onChange 事件,對狀態(tài)進(jìn)行修改,從而反映到 value 上
非受控組件的實(shí)現(xiàn)
- 通過 ref 標(biāo)記一個元素,然后可以通過 this.refs.xx 來獲取這個元素
- 通過 onChange 事件監(jiān)聽到 value 的變化,獲取到這個數(shù)據(jù)
- 然后通過操作 DOM 將數(shù)據(jù)放到需要的地方
下面來實(shí)現(xiàn)雙向綁定:
class Input extends Component {handleChange = (e) => {//=> 這里可以通過 e.target.value 獲取if (e.target === this.refs.a) {this.refs.b.value = e.target.value;} else {this.refs.a.value = e.target.value;}}render() {return (<div onChange={this.handleChange}><input type="text" ref="a" /><input type="text" ref="b" /></div>)} }關(guān)于前端學(xué)習(xí)路線的一些建議,對你一定有用!?www.bilibili.com作者:前端開發(fā)小馬哥鏈接:https://juejin.cn/post/6898512934100533261
來源:掘金
總結(jié)
以上是生活随笔為你收集整理的react方法返回html_React全家桶之React基础(推荐新手必看)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bearshare.exe进程安全吗 b
- 下一篇: 绿联怎么样_移动电源降价了,小米、京选、