摘要:是流行的框架之一,在年及以后將會更加流行。于年首次發(fā)布,多年來廣受歡迎。下面是另一個名為的高階函數(shù)示例,該函數(shù)接受另外兩個函數(shù),分別是和。將所有較小的函數(shù)組合成更大的函數(shù),最終,得到一個應(yīng)用程序,這稱為組合。
React是流行的javascript框架之一,在2019年及以后將會更加流行。React于2013年首次發(fā)布,多年來廣受歡迎。它是一個聲明性的、基于組件的、用于構(gòu)建用戶界面的高效javascript庫。
想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你!
以下是面試前必須了解的話題。
什么是聲明式編程
聲明式編程 vs 命令式編程
什么是函數(shù)式編程
什么是組件設(shè)計模式
React 是什么
React 和 Angular 有什么不同
什么是虛擬DOM及其工作原理
什么是JSX
組件和不同類型
Props 和 State
什么是 PropTypes
如何更新狀態(tài)和不更新狀態(tài)
組件生命周期方法
超越繼承的組合
如何在React中應(yīng)用樣式
什么是Redux及其工作原理
什么是React路由器及其工作原理
什么是錯誤邊界
什么是 Fragments
什么是傳送門(Portals)
什么是 Context
什么是 Hooks
如何提高性能
如何在重新加載頁面時保留數(shù)據(jù)
如何從React中調(diào)用API
總結(jié)
什么是聲明式編程聲明式編程是一種編程范式,它關(guān)注的是你要做什么,而不是如何做。它表達(dá)邏輯而不顯式地定義步驟。這意味著我們需要根據(jù)邏輯的計算來聲明要顯示的組件。它沒有描述控制流步驟。聲明式編程的例子有HTML、SQL等
HTML file
// HTMLDeclarative Programming
SQL file
select * from studens where firstName = "declarative";聲明式編程 vs 命令式編程
聲明式編程的編寫方式描述了應(yīng)該做什么,而命令式編程描述了如何做。在聲明式編程中,讓編譯器決定如何做事情。聲明性程序很容易推理,因為代碼本身描述了它在做什么。
下面是一個例子,數(shù)組中的每個元素都乘以 2,我們使用聲明式map函數(shù),讓編譯器來完成其余的工作,而使用命令式,需要編寫所有的流程步驟。
const numbers = [1,2,3,4,5]; // 聲明式 const doubleWithDec = numbers.map(number => number * 2); console.log(doubleWithDec) // 命令式 const doubleWithImp = []; for(let i=0; i什么是函數(shù)式編程 函數(shù)式編程是聲明式編程的一部分。javascript中的函數(shù)是第一類公民,這意味著函數(shù)是數(shù)據(jù),你可以像保存變量一樣在應(yīng)用程序中保存、檢索和傳遞這些函數(shù)。
函數(shù)式編程有些核心的概念,如下:
不可變性(Immutability)
純函數(shù)(Pure Functions)
數(shù)據(jù)轉(zhuǎn)換(Data Transformations)
高階函數(shù) (Higher-Order Functions)
遞歸
組合
不可變性(Immutability)不可變性意味著不可改變。 在函數(shù)式編程中,你無法更改數(shù)據(jù),也不能更改。 如果要改變或更改數(shù)據(jù),則必須復(fù)制數(shù)據(jù)副本來更改。
例如,這是一個student對象和changeName函數(shù),如果要更改學(xué)生的名稱,則需要先復(fù)制 student 對象,然后返回新對象。
在javascript中,函數(shù)參數(shù)是對實際數(shù)據(jù)的引用,你不應(yīng)該使用 student.firstName =“testing11”,這會改變實際的student 對象,應(yīng)該使用Object.assign復(fù)制對象并返回新對象。
let student = { firstName: "testing", lastName: "testing", marks: 500 } function changeName(student) { // student.firstName = "testing11" //should not do it let copiedStudent = Object.assign({}, student); copiedStudent.firstName = "testing11"; return copiedStudent; } console.log(changeName(student)); console.log(student);純函數(shù)純函數(shù)是始終接受一個或多個參數(shù)并計算參數(shù)并返回數(shù)據(jù)或函數(shù)的函數(shù)。 它沒有副作用,例如設(shè)置全局狀態(tài),更改應(yīng)用程序狀態(tài),它總是將參數(shù)視為不可變數(shù)據(jù)。
我想使用 appendAddress 的函數(shù)向student對象添加一個地址。 如果使用非純函數(shù),它沒有參數(shù),直接更改 student 對象來更改全局狀態(tài)。
使用純函數(shù),它接受參數(shù),基于參數(shù)計算,返回一個新對象而不修改參數(shù)。
let student = { firstName: "testing", lastName: "testing", marks: 500 } // 非純函數(shù) function appendAddress() { student.address = {streetNumber:"0000", streetName: "first", city:"somecity"}; } console.log(appendAddress()); // 純函數(shù) function appendAddress(student) { let copystudent = Object.assign({}, student); copystudent.address = {streetNumber:"0000", streetName: "first", city:"somecity"}; return copystudent; } console.log(appendAddress(student)); console.log(student);數(shù)據(jù)轉(zhuǎn)換我們講了很多關(guān)于不可變性的內(nèi)容,如果數(shù)據(jù)是不可變的,我們?nèi)绾胃淖償?shù)據(jù)。如上所述,我們總是生成原始數(shù)據(jù)的轉(zhuǎn)換副本,而不是直接更改原始數(shù)據(jù)。
再介紹一些 javascript內(nèi)置函數(shù),當(dāng)然還有很多其他的函數(shù),這里有一些例子。所有這些函數(shù)都不改變現(xiàn)有的數(shù)據(jù),而是返回新的數(shù)組或?qū)ο蟆?/p>
let cities = ["irving", "lowell", "houston"]; // we can get the comma separated list console.log(cities.join(",")) // irving,lowell,houston // if we want to get cities start with i const citiesI = cities.filter(city => city[0] === "i"); console.log(citiesI) // [ "irving" ] // if we want to capitalize all the cities const citiesC = cities.map(city => city.toUpperCase()); console.log(citiesC) // [ "IRVING", "LOWELL", "HOUSTON" ]高階函數(shù)高階函數(shù)是將函數(shù)作為參數(shù)或返回函數(shù)的函數(shù),或者有時它們都有。 這些高階函數(shù)可以操縱其他函數(shù)。
Array.map,Array.filter和Array.reduce是高階函數(shù),因為它們將函數(shù)作為參數(shù)。
const numbers = [10,20,40,50,60,70,80] const out1 = numbers.map(num => num * 100); console.log(out1); // [ 1000, 2000, 4000, 5000, 6000, 7000, 8000 ] const out2 = numbers.filter(num => num > 50); console.log(out2); // [ 60, 70, 80 ] const out3 = numbers.reduce((out,num) => out + num); console.log(out3); // 330下面是另一個名為isPersonOld的高階函數(shù)示例,該函數(shù)接受另外兩個函數(shù),分別是 message和isYoung 。
const isYoung = age => age < 25; const message = msg => "He is "+ msg; function isPersonOld(age, isYoung, message) { const returnMessage = isYoung(age)?message("young"):message("old"); return returnMessage; } // passing functions as an arguments console.log(isPersonOld(13,isYoung,message)) // He is young遞歸遞歸是一種函數(shù)在滿足一定條件之前調(diào)用自身的技術(shù)。只要可能,最好使用遞歸而不是循環(huán)。你必須注意這一點,瀏覽器不能處理太多遞歸和拋出錯誤。
下面是一個演示遞歸的例子,在這個遞歸中,打印一個類似于樓梯的名稱。我們也可以使用for循環(huán),但只要可能,我們更喜歡遞歸。
function printMyName(name, count) { if(count <= name.length) { console.log(name.substring(0,count)); printMyName(name, ++count); } } console.log(printMyName("Bhargav", 1)); /* B Bh Bha Bhar Bharg Bharga Bhargav */ // withotu recursion var name = "Bhargav" var output = ""; for(let i=0; i組合 在React中,我們將功能劃分為小型可重用的純函數(shù),我們必須將所有這些可重用的函數(shù)放在一起,最終使其成為產(chǎn)品。 將所有較小的函數(shù)組合成更大的函數(shù),最終,得到一個應(yīng)用程序,這稱為組合。
實現(xiàn)組合有許多不同方法。 我們從Javascript中了解到的一種常見方法是鏈接。 鏈接是一種使用點表示法調(diào)用前一個函數(shù)的返回值的函數(shù)的方法。
這是一個例子。 我們有一個name,如果firstName和lastName大于5個單詞的大寫字母,剛返回,并且打印名稱的名稱和長度。
const name = "Bhargav Bachina"; const output = name.split(" ") .filter(name => name.length > 5) .map(val => { val = val.toUpperCase(); console.log("Name:::::"+val); console.log("Count::::"+val.length); return val; }); console.log(output) /* Name:::::BHARGAV Count::::7 Name:::::BACHINA Count::::7 [ "BHARGAV", "BACHINA" ] */在React中,我們使用了不同于鏈接的方法,因為如果有30個這樣的函數(shù),就很難進(jìn)行鏈接。這里的目的是將所有更簡單的函數(shù)組合起來生成一個更高階的函數(shù)。
const name = compose( splitmyName, countEachName, comvertUpperCase, returnName ) console.log(name);什么是 ReactReact是一個簡單的javascript UI庫,用于構(gòu)建高效、快速的用戶界面。它是一個輕量級庫,因此很受歡迎。它遵循組件設(shè)計模式、聲明式編程范式和函數(shù)式編程概念,以使前端應(yīng)用程序更高效。它使用虛擬DOM來有效地操作DOM。它遵循從高階組件到低階組件的單向數(shù)據(jù)流。
React 與 Angular 有何不同?Angular是一個成熟的MVC框架,帶有很多特定的特性,比如服務(wù)、指令、模板、模塊、解析器等等。React是一個非常輕量級的庫,它只關(guān)注MVC的視圖部分。
Angular遵循兩個方向的數(shù)據(jù)流,而React遵循從上到下的單向數(shù)據(jù)流。React在開發(fā)特性時給了開發(fā)人員很大的自由,例如,調(diào)用API的方式、路由等等。我們不需要包括路由器庫,除非我們需要它在我們的項目。
什么是Virtual DOM及其工作原理React 使用 Virtual DOM 來更新真正的 DOM,從而提高效率和速度。 我們來詳細(xì)討論這些。
什么是Virtual DOM瀏覽器遵循HTML指令來構(gòu)造文檔對象模型(DOM)。當(dāng)瀏覽器加載HTML并呈現(xiàn)用戶界面時,HTML文檔中的所有元素都變成DOM元素。
DOM是從根元素開始的元素層次結(jié)構(gòu)。例如,看看下面的HTML。
This is heading
this is paragraph
This is just a paragraon
This is heading
this is paragraph
This is just a paragraon
This is heading
this is paragraph
This is just a paragraon
當(dāng)在瀏覽器中加載這個HTML時,所有這些HTML元素都被轉(zhuǎn)換成DOM元素,如下所示
當(dāng)涉及到SPA應(yīng)用程序時,首次加載index.html,并在index.html本身中加載更新后的數(shù)據(jù)或另一個html。當(dāng)用戶瀏覽站點時,我們使用新內(nèi)容更新相同的index.html。每當(dāng)DOM發(fā)生更改時,瀏覽器都需要重新計算CSS、進(jìn)行布局并重新繪制web頁面。
React 使用 Virtual DOM 有效地重建 DOM。 對于我們來說,這使得DOM操作的一項非常復(fù)雜和耗時的任務(wù)變得更加容易。 React從開發(fā)人員那里抽象出所有這些,以便在Virtual DOM的幫助下構(gòu)建高效的UI。
虛擬DOM是如何工作的虛擬DOM只不過是真實 DOM 的 javascript對象表示。 與更新真實 DOM 相比,更新 javascript 對象更容易,更快捷。 考慮到這一點,讓我們看看它是如何工作的。
React將整個DOM副本保存為虛擬DOM
每當(dāng)有更新時,它都會維護兩個虛擬DOM,以比較之前的狀態(tài)和當(dāng)前狀態(tài),并確定哪些對象已被更改。 例如,段落文本更改為更改。
現(xiàn)在,它通過比較兩個虛擬DOM 差異,并將這些變化更新到實際DOM
一旦真正的DOM更新,它也會更新UI
什么是 JSXJSX是javascript的語法擴展。它就像一個擁有javascript全部功能的模板語言。它生成React元素,這些元素將在DOM中呈現(xiàn)。React建議在組件使用JSX。在JSX中,我們結(jié)合了javascript和HTML,并生成了可以在DOM中呈現(xiàn)的react元素。
下面是JSX的一個例子。我們可以看到如何將javascript和HTML結(jié)合起來。如果HTML中包含任何動態(tài)變量,我們應(yīng)該使用表達(dá)式{}。
import React from "react"; export const Header = () => { const heading = "TODO App" return(組件和不同類型) }{heading}
React 中一切都是組件。 我們通常將應(yīng)用程序的整個邏輯分解為小的單個部分。 我們將每個多帶帶的部分稱為組件。 通常,組件是一個javascript函數(shù),它接受輸入,處理它并返回在UI中呈現(xiàn)的React元素。
在React中有不同類型的組件。讓我們詳細(xì)看看。
函數(shù)/無狀態(tài)/展示組件函數(shù)或無狀態(tài)組件是一個純函數(shù),它可接受接受參數(shù),并返回react元素。這些都是沒有任何副作用的純函數(shù)。這些組件沒有狀態(tài)或生命周期方法,這里有一個例子。
import React from "react"; import Jumbotron from "react-bootstrap/Jumbotron"; export const Header = () => { return(類/有狀態(tài)組件) } TODO App
類或有狀態(tài)組件具有狀態(tài)和生命周期方可能通過 setState()方法更改組件的狀態(tài)。類組件是通過擴展React創(chuàng)建的。它在構(gòu)造函數(shù)中初始化,也可能有子組件,這里有一個例子。
import React from "react"; import "../App.css"; import { ToDoForm } from "./todoform"; import { ToDolist } from "./todolist"; export class Dashboard extends React.Component { constructor(props){ super(props); this.state = { } } render() { return (受控組件); } }受控組件是在 React 中處理輸入表單的一種技術(shù)。表單元素通常維護它們自己的狀態(tài),而react則在組件的狀態(tài)屬性中維護狀態(tài)。我們可以將兩者結(jié)合起來控制輸入表單。這稱為受控組件。因此,在受控組件表單中,數(shù)據(jù)由React組件處理。
這里有一個例子。當(dāng)用戶在 todo 項中輸入名稱時,調(diào)用一個javascript函數(shù)handleChange捕捉每個輸入的數(shù)據(jù)并將其放入狀態(tài),這樣就在 handleSubmit中的使用數(shù)據(jù)。
import React from "react"; import Form from "react-bootstrap/Form"; import Button from "react-bootstrap/Button"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; export class ToDoForm extends React.Component { constructor(props) { super(props); this.state = {value: ""}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert("A name was submitted: " + this.state.value); event.preventDefault(); } render() { return (非受控組件); } }Item 大多數(shù)情況下,建議使用受控組件。有一種稱為非受控組件的方法可以通過使用Ref來處理表單數(shù)據(jù)。在非受控組件中,Ref用于直接從DOM訪問表單值,而不是事件處理程序。
我們使用Ref構(gòu)建了相同的表單,而不是使用React狀態(tài)。 我們使用React.createRef() 定義Ref并傳遞該輸入表單并直接從handleSubmit方法中的DOM訪問表單值。
import React from "react"; import Form from "react-bootstrap/Form"; import Button from "react-bootstrap/Button"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; export class ToDoForm extends React.Component { constructor(props) { super(props); this.state = {value: ""}; this.input = React.createRef(); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { alert("A name was submitted: " + this.input.current.value); event.preventDefault(); } render() { return (容器組件); } }Item 容器組件是處理獲取數(shù)據(jù)、訂閱 redux 存儲等的組件。它們包含展示組件和其他容器組件,但是里面從來沒有html。
高階組件高階組件是將組件作為參數(shù)并生成另一個組件的組件。 Redux connect是高階組件的示例。 這是一種用于生成可重用組件的強大技術(shù)。
Props 和 StateProps 是只讀屬性,傳遞給組件以呈現(xiàn)UI和狀態(tài),我們可以隨時間更改組件的輸出。
下面是一個類組件的示例,它在構(gòu)造函數(shù)中定義了props和state,每當(dāng)使用this.setState() 修改狀態(tài)時,將再次調(diào)用 render( ) 函數(shù)來更改UI中組件的輸出。
import React from "react"; import "../App.css"; export class Dashboard extends React.Component { constructor(props){ super(props); this.state = { name: "some name" } } render() { // reading state const name = this.state.name; //reading props const address = this.props.address; return (什么是PropTypes{name} {address}); } }隨著時間的推移,應(yīng)用程序會變得越來越大,因此類型檢查非常重要。PropTypes為組件提供類型檢查,并為其他開發(fā)人員提供很好的文檔。如果react項目不使用 Typescript,建議為組件添加 PropTypes。
如果組件沒有收到任何 props,我們還可以為每個組件定義要顯示的默認(rèn) props。這里有一個例子。UserDisplay有三個 prop:name、address和age,我們正在為它們定義默認(rèn)的props 和 prop類型。
import React from "react"; import PropTypes from "prop-types"; export const UserDisplay = ({name, address, age}) => { UserDisplay.defaultProps = { name: "myname", age: 100, address: "0000 onestreet" }; return ( <>如何更新狀態(tài)以及如何不更新Name:{name}Address:{address}> ) } UserDisplay.propTypes = { name: PropTypes.string.isRequired, address: PropTypes.objectOf(PropTypes.string), age: PropTypes.number.isRequired }Age:{age}你不應(yīng)該直接修改狀態(tài)??梢栽跇?gòu)造函數(shù)中定義狀態(tài)值。直接使用狀態(tài)不會觸發(fā)重新渲染。React 使用this.setState()時合并狀態(tài)。
// 錯誤方式 this.state.name = "some name" // 正確方式 this.setState({name:"some name"})使用this.setState()的第二種形式總是更安全的,因為更新的props和狀態(tài)是異步的。這里,我們根據(jù)這些 props 更新狀態(tài)。
// 錯誤方式 this.setState({ timesVisited: this.state.timesVisited + this.props.count }) // 正確方式 this.setState((state, props) => { timesVisited: state.timesVisited + props.count });組件生命周期方法組件在進(jìn)入和離開DOM時要經(jīng)歷一系列生命周期方法,下面是這些生命周期方法。
componentWillMount()在渲染前調(diào)用,在客戶端也在服務(wù)端,它只發(fā)生一次。
componentDidMount()在第一次渲染后調(diào)用,只在客戶端。之后組件已經(jīng)生成了對應(yīng)的DOM結(jié)構(gòu),可以通過this.getDOMNode()來進(jìn)行訪問。 如果你想和其他JavaScript框架一起使用,可以在這個方法中調(diào)用setTimeout, setInterval或者發(fā)送AJAX請求等操作(防止異部操作阻塞UI)。
componentWillReceiveProps()在組件接收到一個新的 prop (更新后)時被調(diào)用。這個方法在初始化render時不會被調(diào)用。
shouldComponentUpdate()返回一個布爾值。在組件接收到新的props或者state時被調(diào)用。在初始化時或者使用forceUpdate時不被調(diào)用。 可以在你確認(rèn)不需要更新組件時使用。
componentWillUpdate()在組件接收到新的props或者state但還沒有render時被調(diào)用。在初始化時不會被調(diào)用。
componentDidUpdate()在組件完成更新后立即調(diào)用。在初始化時不會被調(diào)用。
componentWillUnMount()件從 DOM 中移除的時候立刻被調(diào)用。
getDerivedStateFromError()這個生命周期方法在ErrorBoundary類中使用。實際上,如果使用這個生命周期方法,任何類都會變成ErrorBoundary。這用于在組件樹中出現(xiàn)錯誤時呈現(xiàn)回退UI,而不是在屏幕上顯示一些奇怪的錯誤。
componentDidCatch()這個生命周期方法在ErrorBoundary類中使用。實際上,如果使用這個生命周期方法,任何類都會變成ErrorBoundary。這用于在組件樹中出現(xiàn)錯誤時記錄錯誤。
超越繼承的組合在React中,我們總是使用組合而不是繼承。我們已經(jīng)在函數(shù)式編程部分討論了什么是組合。這是一種結(jié)合簡單的可重用函數(shù)來生成高階組件的技術(shù)。下面是一個組合的例子,我們在 dashboard 組件中使用兩個小組件todoForm和todoList。
import React from "react"; import "../App.css"; import { ToDoForm } from "./todoform"; import { ToDolist } from "./todolist"; export class Dashboard extends React.Component { render() { return (如何在React中應(yīng)用樣式); } }將樣式應(yīng)用于React組件有三種方法。
外部樣式表在此方法中,你可以將外部樣式表導(dǎo)入到組件使用類中。 但是你應(yīng)該使用className而不是class來為React元素應(yīng)用樣式, 這里有一個例子。
import React from "react"; import "./App.css"; import { Header } from "./header/header"; import { Footer } from "./footer/footer"; import { Dashboard } from "./dashboard/dashboard"; import { UserDisplay } from "./userdisplay"; function App() { return (內(nèi)聯(lián)樣式); } export default App;在這個方法中,我們可以直接將 props 傳遞給HTML元素,屬性為style。這里有一個例子。這里需要注意的重要一點是,我們將javascript對象傳遞給style,這就是為什么我們使用 backgroundColor 而不是CSS方法backbackground -color。
import React from "react"; export const Header = () => { const heading = "TODO App" return(定義樣式對象并使用它) }{heading}
因為我們將javascript對象傳遞給style屬性,所以我們可以在組件中定義一個style對象并使用它。下面是一個示例,你也可以將此對象作為 props 傳遞到組件樹中。
import React from "react"; const footerStyle = { width: "100%", backgroundColor: "green", padding: "50px", font: "30px", color: "white", fontWeight: "bold" } export const Footer = () => { return(什么是Redux及其工作原理All Rights Reserved 2019) }Redux 是 React的一個狀態(tài)管理庫,它基于flux。 Redux簡化了React中的單向數(shù)據(jù)流。 Redux將狀態(tài)管理完全從React中抽象出來。
它是如何工作的在React中,組件連接到 redux ,如果要訪問 redux,需要派出一個包含 id和負(fù)載(payload) 的 action。action 中的 payload 是可選的,action 將其轉(zhuǎn)發(fā)給 Reducer。
當(dāng)reducer收到action時,通過 swithc...case 語法比較 action 中type。 匹配時,更新對應(yīng)的內(nèi)容返回新的 state。
當(dāng)Redux狀態(tài)更改時,連接到Redux的組件將接收新的狀態(tài)作為props。當(dāng)組件接收到這些props時,它將進(jìn)入更新階段并重新渲染 UI。
Redux 循環(huán)細(xì)節(jié)讓我們詳細(xì)看看整個redux 循環(huán)細(xì)節(jié)。
Action: Action 只是一個簡單的json對象,type 和有payload作為鍵。type 是必須要有的,payload是可選的。下面是一個 action 的例子。
// action { type:"SEND_EMAIL", payload: data };Action Creators:這些是創(chuàng)建Actions的函數(shù),因此我們在派發(fā)action時不必在組件中手動編寫每個 action。 以下是 action creator 的示例。
// action creator export function sendEamil(data) { return { type:"SEND_EMAIL", payload: data}; }Reducers:Reducers 是純函數(shù),它將 action和當(dāng)前 state 作為參數(shù),計算必要的邏輯并返回一個新r的state。 這些 Reducers 沒有任何副作用。 它不會改變 state 而是總是返回 state 。
export default function emailReducer(state = [], action){ switch(action.type) { case "SEND_EMAIL": return Object.assign({}, state, { email: action.payload }); default: return state; } }組件如何與 redux 進(jìn)行連接mapStateToProps:此函數(shù)將state映射到 props 上,因此只要state發(fā)生變化,新 state 會重新映射到 props。 這是訂閱store的方式。
mapDispatchToProps:此函數(shù)用于將 action creators 綁定到你的props 。以便我們可以在第12行中使用This . props.actions.sendemail()來派發(fā)一個動作。
connect和bindActionCreators來自 redux。 前者用于連接 store ,如第22行,后者用于將 action creators 綁定到你的 props ,如第20行。
// import connect import { connect } from "react-redux" import { bindActionCreators } from "redux" // import action creators import * as userActions from "../../../actions/userActions"; export class User extends React.Component { handleSubmit() { // dispatch an action this.props.actions.sendEmail(this.state.email); } } // you are mapping you state props const mapStateToProps = (state, ownProps) => ({user: state.user}) // you are binding your action creators to your props const mapDispatchToProps = (dispatch) => ({actions: bindActionCreators(userActions, dispatch)}) export default connect(mapStateToProps, mapDispatchToProps)(User);什么是 React Router Dom 及其工作原理react-router-dom是應(yīng)用程序中路由的庫。 React庫中沒有路由功能,需要多帶帶安裝react-router-dom。
react-router-dom 提供兩個路由器BrowserRouter和HashRoauter。前者基于rul的pathname段,后者基于hash段。
前者:http://127.0.0.1:3000/article/num1 后者:http://127.0.0.1:3000/#/article/num1(不一定是這樣,但#是少不了的)react-router-dom 組件BrowserRouter 和 HashRouter 是路由器。
Route 用于路由匹配。
Link 組件用于在應(yīng)用程序中創(chuàng)建鏈接。 它將在HTML中渲染為錨標(biāo)記。
NavLink是突出顯示當(dāng)前活動鏈接的特殊鏈接。
Switch 不是必需的,但在組合路由時很有用。
Redirect 用于強制路由重定向
下面是組件中的Link、NavLink和Redirect 的例子
// normal link Home // link which highlights currentlu active route with the given class nameReact // you can redirect to this url以下是 react router 組件的示例。 如果你查看下面的示例,我們將匹配路徑并使用Switch和Route呈現(xiàn)相應(yīng)的組件。
import React from "react" // import react router DOM elements import { Switch, Route, Redirect } from "react-router-dom" import ComponentA from "../common/compa" import ComponentB from "../common/compb" import ComponentC from "../common/compc" import ComponentD from "../common/compd" import ComponentE from "../common/compe" const Layout = ({ match }) => { return(什么是錯誤邊界)} export default Layout在 React 中,我們通常有一個組件樹。如果任何一個組件發(fā)生錯誤,它將破壞整個組件樹。沒有辦法捕捉這些錯誤,我們可以用錯誤邊界優(yōu)雅地處理這些錯誤。
錯誤邊界有兩個作用
如果發(fā)生錯誤,顯示回退UI
記錄錯誤
下面是ErrorBoundary類的一個例子。如果類實現(xiàn)了 getDerivedStateFromError或componentDidCatch 這兩個生命周期方法的任何一下,,那么這個類就會成為ErrorBoundary。前者返回{hasError: true}來呈現(xiàn)回退UI,后者用于記錄錯誤。
import React from "react" export class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { hasError: true }; } componentDidCatch(error, info) { // You can also log the error to an error reporting service console.log("Error::::", error); } render() { if (this.state.hasError) { // You can render any custom fallback UI returnOOPS!. WE ARE LOOKING INTO IT.
; } return this.props.children; } }以下是我們?nèi)绾卧谄渲幸粋€組件中使用ErrorBoundary。使用ErrorBoundary類包裹 ToDoForm和ToDoList。 如果這些組件中發(fā)生任何錯誤,我們會記錄錯誤并顯示回退UI。
import React from "react"; import "../App.css"; import { ToDoForm } from "./todoform"; import { ToDolist } from "./todolist"; import { ErrorBoundary } from "../errorboundary"; export class Dashboard extends React.Component { render() { return (什么是 Fragments); } }在React中,我們需要有一個父元素,同時從組件返回React元素。有時在DOM中添加額外的節(jié)點會很煩人。使用 Fragments,我們不需要在DOM中添加額外的節(jié)點。我們只需要用 React.Fragment 或才簡寫 <> 來包裹內(nèi)容就行了。如下 所示:
// Without Fragments return (什么是傳送門(Portals)) // With Fragments return () // shorthand notation Fragments return ( <> > ) 默認(rèn)情況下,所有子組件都在UI上呈現(xiàn),具體取決于組件層次結(jié)構(gòu)。Portal 提供了一種將子節(jié)點渲染到存在于父組件以外的 DOM 節(jié)點的優(yōu)秀的方案。
這里有一個例子。默認(rèn)情況下,父組件在DOM層次結(jié)構(gòu)中有子組件。
我們可以將 children 組件移出parent 組件并將其附加 id 為 someid 的 Dom 節(jié)點下。
首先,獲取 id 為 someid,我們在constrcutorand中創(chuàng)建一個元素div,將child附加到componentDidMount中的someRoot。 最后,我們在ReactDOM.createPortal(this.props.childen),domnode的幫助下將子節(jié)點傳遞給該特定DOM節(jié)點。
首先,先獲取 id 為someid DOM元素,接著在構(gòu)造函數(shù)中創(chuàng)建一個元素div,在 componentDidMount方法中將 someRoot 放到 div 中 。 最后,通過
ReactDOM.createPortal(this.props.childen), domnode)將 children 傳遞到對應(yīng)的節(jié)點下。const someRoot = document.getElementById("someid"); class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement("div"); } componentDidMount() { someRoot.appendChild(this.el); } componentWillUnmount() { someRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } }什么是上下文有時我們必須將props 傳遞給組件樹,即使所有中間組件都不需要這些props 。上下文是一種傳遞props 的方法,而不用在每一層傳遞組件樹。
什么是 HooksHooks 是React版本16.8中的新功能。 請記住,我們不能在函數(shù)組件中使用state ,因為它們不是類組件。Hooks 讓我們在函數(shù)組件中可以使用state 和其他功能。
目前沒有重大變化,我們不必放棄類組件。
Hook 不會影響你對 React 概念的理解。 恰恰相反,Hook 為已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。稍后我們將看到,Hook 還提供了一種更強大的方式來組合他們。
我們可以使用一些鉤子,例如useState,useEffect,useContext,useReducer等。
下面是 Hooks 的基本規(guī)則
Hooks 應(yīng)該在外層使用,不應(yīng)該在循環(huán),條件或嵌套函數(shù)中使用
Hooks 應(yīng)該只在函數(shù)組件中使用。
讓我們看一個例子來理解 hooks。 這是一個函數(shù)組件,它采用props并在UI上顯示這些props。 在useState鉤子的幫助下,我們將這個函數(shù)組件轉(zhuǎn)換為有狀態(tài)組件。 首先,我們在第5行定義狀態(tài),這相當(dāng)于
constructor(props) { super(props); this.state = { name:"myname", age:10, address:"0000 one street" } }useState返回兩個項,一個是user,另一個是setUser函數(shù)。 user 是一個可以在沒有 this關(guān)鍵字的情況下直接使用的對象,setUser是一個可以用來設(shè)置用戶點擊第21行按鈕的狀態(tài)的函數(shù),該函數(shù)等效于以下內(nèi)容。
this.setState({name:"name changed"})
1 import React, { useState } from "react"; 2 3 export const UserDisplay = ({name, address, age}) => { 4 5 const [user, setUser] = useState({ name: "myname", age: 10, address: "0000 onestreet" }); 6 7 return ( 8 <> 9如何提高性能1013Name:11{user.name}121417Address:15{user.address}161821 24 > 25 ) 26 }Age:19{user.age}20我們可以通過多種方式提高應(yīng)用性能,以下這些比較重要:
適當(dāng)?shù)厥褂?b>shouldComponentUpdate生命周期方法。 它避免了子組件的不必要的渲染。 如果樹中有100個組件,則不重新渲染整個組件樹來提高應(yīng)用程序性能。
使用create-react-app來構(gòu)建項目,這會創(chuàng)建整個項目結(jié)構(gòu),并進(jìn)行大量優(yōu)化。
不可變性是提高性能的關(guān)鍵。不要對數(shù)據(jù)進(jìn)行修改,而是始終在現(xiàn)有集合的基礎(chǔ)上創(chuàng)建新的集合,以保持盡可能少的復(fù)制,從而提高性能。
在顯示列表或表格時始終使用 Keys,這會讓 React 的更新速度更快
代碼分離是將代碼插入到多帶帶的文件中,只加載模塊或部分所需的文件的技術(shù)。
如何在重新加載頁面時保留數(shù)據(jù)單頁應(yīng)用程序首先在DOM中加載index.html,然后在用戶瀏覽頁面時加載內(nèi)容,或者從同一index.html中的后端API獲取任何數(shù)據(jù)。
如果通過點擊瀏覽器中的重新加載按鈕重新加載頁面index.html,整個React應(yīng)用程序?qū)⒅匦录虞d,我們將丟失應(yīng)用程序的狀態(tài)。 如何保留應(yīng)用狀態(tài)?
每當(dāng)重新加載應(yīng)用程序時,我們使用瀏覽器localstorage來保存應(yīng)用程序的狀態(tài)。我們將整個存儲數(shù)據(jù)保存在localstorage中,每當(dāng)有頁面刷新或重新加載時,我們從localstorage加載狀態(tài)。
如何在React進(jìn)行API調(diào)用我們使用redux-thunk在React中調(diào)用API。因為reduce是純函數(shù),所以沒有副作用,比如調(diào)用API。
因此,我們必須使用redux-thunk從 action creators 那里進(jìn)行 API 調(diào)用。Action creator 派發(fā)一個action,將來自API的數(shù)據(jù)放入action 的 payload 中。Reducers 接收我們在上面的redux循環(huán)中討論的數(shù)據(jù),其余的過程也是相同的。
redux-thunk是一個中間件。一旦它被引入到項目中,每次派發(fā)一個action時,都會通過thunk傳遞。如果它是一個函數(shù),它只是等待函數(shù)處理并返回響應(yīng)。如果它不是一個函數(shù),它只是正常處理。
這里有一個例子。sendEmailAPI是從組件中調(diào)用的函數(shù),它接受一個數(shù)據(jù)并返回一個函數(shù),其中dispatch作為參數(shù)。我們使用redux-thunk調(diào)用API apiservice,并等待收到響應(yīng)。一旦接收到響應(yīng),我們就使用payload 派發(fā)一個action 。
import apiservice from "../services/apiservice"; export function sendEmail(data) { return { type:"SEND_EMAIL", payload: data }; } export function sendEmailAPI(email) { return function(dispatch) { return apiservice.callAPI(email).then(data => { dispatch(sendEmail(data)); }); } }總結(jié)要想有把握的面試,必須充分了解上述所有主題。 即使你目前正在使用React,理解這些概念也能增強你在職場中信心。
代碼部署后可能存在的BUG沒法實時知道,事后為了解決這些BUG,花了大量的時間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個好用的BUG監(jiān)控工具 Fundebug。
交流這篇來來回回整理了快五天,大家給個贊唄!
干貨系列文章匯總?cè)缦?,覺得不錯點個Star,歡迎 加群 互相學(xué)習(xí)。
https://github.com/qq44924588...我是小智,公眾號「大遷世界」作者,對前端技術(shù)保持學(xué)習(xí)愛好者。我會經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!
關(guān)注公眾號,后臺回復(fù)福利,即可看到福利,你懂的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/104279.html
摘要:分享一個比較完整的項目供大家交流學(xué)習(xí),這個項目的英文簡介項目地址在線演示翻譯過來呢就是一個涉及面較廣的使用豆瓣作為數(shù)據(jù)源的。 分享一個比較完整的Vue2+項目供大家交流學(xué)習(xí),這個項目的英文簡介:Awesome douban DEMO created with Vue2.x + Vuex + Vue-router + vue-resource 項目地址:https://github.co...
摘要:技術(shù)一面一面主要考察基礎(chǔ),有些會有技術(shù)筆試,比如騰訊,。騰訊的面試官就很喜歡問,安全,瀏覽器緩存方面的問題,計算機基礎(chǔ),但是要懂為什么。 這篇文章簡單總結(jié)下2018年內(nèi)我的一些前端面試經(jīng)歷, 在這簡單分享一下,希望對大家有所啟發(fā)。 樓主在深圳,畢業(yè)兩年。面的主要是深圳的幾家公司。 包括: 騰訊, 螞蟻金服, Lazada, Shopee, 有贊 等 。 樓主在準(zhǔn)備面試前, 想著復(fù)習(xí)一...
摘要:整理收藏一些優(yōu)秀的文章及大佬博客留著慢慢學(xué)習(xí)原文協(xié)作規(guī)范中文技術(shù)文檔協(xié)作規(guī)范阮一峰編程風(fēng)格凹凸實驗室前端代碼規(guī)范風(fēng)格指南這一次,徹底弄懂執(zhí)行機制一次弄懂徹底解決此類面試問題瀏覽器與的事件循環(huán)有何區(qū)別筆試題事件循環(huán)機制異步編程理解的異步 better-learning 整理收藏一些優(yōu)秀的文章及大佬博客留著慢慢學(xué)習(xí) 原文:https://www.ahwgs.cn/youxiuwenzhan...
摘要:實際上是格林威治標(biāo)準(zhǔn)時間的同義詞默認(rèn)情況下,中的幾乎每個日期方法除了一個都是本地時間。如果你住在格林威治標(biāo)準(zhǔn)時間晚的的地區(qū),你會得到一個日期是月日。需要知道對象日期方法。 為了保證的可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! JS中的 Date 很奇怪。當(dāng)我們需要處理日期和時間的時候比較麻煩,經(jīng)常借助像date-fns和 Mom...
摘要:先說下我面試情況,我一共面試了家公司。篇在我面試的眾多公司里,只有同城的面問到相關(guān)問題,其他公司壓根沒問。我自己回答的是自己開發(fā)組件面臨的問題。完全不用擔(dān)心對方到時候打電話核對的問題。 2019的5月9號,離發(fā)工資還有1天的時候,我的領(lǐng)導(dǎo)親切把我叫到辦公室跟我說:阿郭,我們公司要倒閉了,錢是沒有的啦,為了不耽誤你,你趕緊出去找工作吧。聽到這話,我虎軀一震,這已經(jīng)是第2個月沒工資了。 公...
閱讀 2765·2021-11-11 16:54
閱讀 2403·2021-10-09 09:44
閱讀 2664·2019-08-30 15:54
閱讀 1984·2019-08-30 11:24
閱讀 1249·2019-08-29 17:03
閱讀 2165·2019-08-29 16:22
閱讀 2140·2019-08-29 13:11
閱讀 1111·2019-08-29 12:14