初探react,用react实现一个todoList功能
初探react,用react實現(xiàn)一個todoList功能
- 🛰?前言
- 🚀一、react基礎(chǔ)
- 1. react簡介
- 2. 開發(fā)環(huán)境搭建
- 3. 工程目錄文件簡介
- 4. react中最基礎(chǔ)的JSX語法
- 🛸二、使用react編寫TodoList功能
- 1. 頁面構(gòu)思
- 2. React中的響應(yīng)式設(shè)計思想和事件綁定
- 3. 實現(xiàn)TodoList新增刪除功能
- (1)新增功能
- (2)刪除功能
- 🪐三、對TodoList功能進(jìn)行進(jìn)階操作
- 1. JSX語法細(xì)節(jié)補(bǔ)充
- (1)自動轉(zhuǎn)義
- (2)光標(biāo)聚焦
- 2. 拆分組件與組件之間的傳值
- 3. TodoList代碼優(yōu)化
- 🌠四、圍繞React衍生出的思考
- 🌌五、結(jié)束語
- ??彩蛋
🛰?前言
對于前端而言, react 是前端三大主流框架之一。而在現(xiàn)實生產(chǎn)中,基本上很多大型公司也會偏向于使用 react ,原因在于 react 的 diy 能力比起其他框架也會稍微要更好一些~
緊跟著新技術(shù)的步伐,周一也開始學(xué)期了 react 。那在下面的文章中,將講解關(guān)于 react 的一些基礎(chǔ)知識點,同時呢,也將用 react 來實現(xiàn)一個 TodoList 的功能。
叮咚,開始奇妙的 eract 之旅~🚋
🚀一、react基礎(chǔ)
在對 todoList 功能進(jìn)行設(shè)計之前,我們先來了解一點 react 相關(guān)的基礎(chǔ)知識。
1. react簡介
對于 reactjs 來說,需要了解的一些基礎(chǔ)知識主要有以下幾點:
- reactjs → react native → react VR ;
- 由 Facebook 推出的一款框架,于 2013 年開源于社區(qū);
- react 擁有豐富的函數(shù)式編程;
- react 目前在全球范圍內(nèi),是使用人數(shù)最多的前端框架,同時它擁有健全的文檔與完善的社區(qū);
- React Fiber 是 React 16 的版本,它為 React 做了很多底層的優(yōu)化。
2. 開發(fā)環(huán)境搭建
在進(jìn)入 react 的基礎(chǔ)學(xué)習(xí)之前,我們首先來搭建 react 的開發(fā)環(huán)境。對于 react 的環(huán)境搭建來說,一般有兩種方式,分別是:
- 通過引入 .js 文件來使用 React ;
- 通過腳手架工具來編碼,比如 GRUNT 、 Gulp 和 webpack ;
- 使用 create-react-app 來搭建環(huán)境。
那么現(xiàn)在,我們用 create-react-app 來搭建一個 react 項目。具體命令行如下:
npx create-react-app my-app cd my-app npm start3. 工程目錄文件簡介
初始化完一個項目后,我們來了解下 react 的項目結(jié)構(gòu)。具體如下:
├── public├── favicon.ico 網(wǎng)頁icon├── index.html 首頁的html模板├── manifest.json 緩存文件 ├── src├── App.css ├── App.js 填寫組件的內(nèi)容├── App.test.js 自動化測試文件├── index.css├── index.js 整個程序運行的入口文件├── logo.svg├── registerServiceWorker 借助網(wǎng)頁寫手機(jī)app的功能 ├── README.md 項目的說明文件 ├── yarn.lock 項目依賴安裝包的一些版本號4. react中最基礎(chǔ)的JSX語法
以前我們在寫像 <div></div> 這種類似的語法時,一般都是寫在 HTML 文件里面。那么,在 react 中,像 <div></div> 這種類型的代碼,是在 JS 中去寫的。因此,在 js 中寫的 html 代碼,被稱之為 jsx 語法。
值得注意的是,在 react 中使用自己定義的組件時,組件名必須以大寫為開頭,小寫開頭在 jsx 中是不支持的,這一點需要稍微注意一下。
所以,一般看到以大寫為開頭時,比如 <App /> ,則說明是我們自己定義的組件。如果是小寫為開頭時,則一般是原始的 HTML5 標(biāo)簽,如 <div></div> 。
🛸二、使用react編寫TodoList功能
1. 頁面構(gòu)思
首先,我們需要先來對頁面的內(nèi)容進(jìn)行構(gòu)造。我們在項目的 src文件夾下創(chuàng)建一個文件,命名為 TodoList 。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {render() {return (<Fragment><div><input /><button></button></div><ul><li>學(xué)英語</li><li>Learning React</li></ul></Fragment>)} }export default TodoList;此時瀏覽器的顯示效果如下:
2. React中的響應(yīng)式設(shè)計思想和事件綁定
上面我們簡單了顯示了 todolist 的基本功能,那現(xiàn)在,我們想要實現(xiàn)的是,點擊提交按鈕,可以把 input 框里面的內(nèi)容顯示在列表下方,這又該怎么處理呢?
如果按照我們正常的思維來想的話,我們可能會覺得,在提交按鈕中綁定一個事件,之后呢,當(dāng)點擊綁定按鈕時,獲取到 input 框的值,進(jìn)行綁定提交。
但事實上, react 強(qiáng)調(diào)的是,我們不要直接操作 DOM ,而是要操作數(shù)據(jù)。當(dāng)數(shù)據(jù)發(fā)生變化時, react 會自動地感知到我們數(shù)據(jù)發(fā)生的變化,會自動地幫我們生成 DOM 。
因此,在寫 react 時,我們不需要關(guān)心 DOM 層面的操作,只需要去關(guān)心數(shù)據(jù)層面的操作即可。
現(xiàn)在,我們先來監(jiān)聽 input 框的值。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'hello!!',list: []}}render() {return (<Fragment><div><input value = {this.state.inputValue}onChange = {this.handleInputChange.bind(this)}/><button>提交</button></div><ul><li>學(xué)英語</li><li>Learning React</li></ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})} }export default TodoList;此時瀏覽器的打印效果為:
大家可以看到,我們正確的使得 input 框響應(yīng)到了數(shù)據(jù)。
那在上面的這段代碼中,需要了解的知識點有以下幾點。分別是:
- state 負(fù)責(zé)存儲組件中的數(shù)據(jù);
- 如果想要在 html 代碼中用一些 js 的表達(dá)式,那么要記得用 {} 進(jìn)行包裹;
- 在進(jìn)行事件綁定時,記得使用 bind(this) 對事件的作用域進(jìn)行變更;
- 當(dāng)你想要改變數(shù)據(jù)項時,不能直接使用 this.state 來改變數(shù)據(jù)的值,要通過 setState 函數(shù)來進(jìn)行改變。
3. 實現(xiàn)TodoList新增刪除功能
(1)新增功能
在上面的例子中,我們實現(xiàn)了 input 框中值的獲取。那現(xiàn)在,我們要來實現(xiàn)點擊提交這個按鈕,能夠?qū)崿F(xiàn)對 input 框中值的新增。同樣地,是在 TodoList.js 文件下進(jìn)行修改。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}}render() {return (<Fragment><div><input value = {this.state.inputValue}onChange = {this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return <li key={index}>{ item }</li>})}</ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})// console.log(e.target.value)}handleBtnClick() {// ... 展開運算符會將之前的數(shù)組進(jìn)行展開,并生成一個全新的數(shù)組// 將input框的值和list的值進(jìn)行合并形成一個新的數(shù)組this.setState({list: [...this.state.list, this.state.inputValue],inputValue: ''})} }export default TodoList;此時瀏覽器的顯示效果如下:
在上面的代碼中,需要了解的知識點有:
- 我們先在 button 中綁定了 handleBtnClick 事件;
- 之后通過展開運算符 ... ,將數(shù)組的內(nèi)容給合并到 list 數(shù)組中;
- 最后,使用 js 中的 map() 方法,將數(shù)組列表中的內(nèi)容給遍歷出來。
(2)刪除功能
繼續(xù),我們來實現(xiàn)刪除功能。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}}render() {return (<Fragment><div><inputvalue={this.state.inputValue}onChange={this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return (<likey={index}onClick={this.handleItemDelete.bind(this, index)}>{item}</li>)})}</ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})}handleBtnClick() {this.setState({list: [...this.state.list, this.state.inputValue],inputValue: ''})}handleItemDelete(index) {const list = [...this.state.list];list.splice(index, 1);this.setState({list: list})} }export default TodoList;在上面的代碼中,我們在每一個 <li> 標(biāo)簽下綁定了 handleItemDelete 事件,之后呢,通過傳遞它的 id 值 index ,同時,配合 splice() 方法,來刪除掉掉 list 中具體的內(nèi)容。
值得注意的是,在 react 中,它是不允許我們對 state 做任何改變的。比如說,我們想要把上面刪除代碼的邏輯這么寫:
handleItemDelete(index) {this.state.list.splice(index, 1);this.setState({list: this.state.list}) }如果我們直接去操作 this 來改變最后的結(jié)果,這會使得函數(shù)變得很難用。同時,這種方式在 react 中也是不允許滴!這是應(yīng)該注意的一個點!
🪐三、對TodoList功能進(jìn)行進(jìn)階操作
1. JSX語法細(xì)節(jié)補(bǔ)充
(1)自動轉(zhuǎn)義
如果在 jsx 中,我們希望顯示一些內(nèi)容,且這些內(nèi)容我們希望它自動轉(zhuǎn)義。像下圖這樣:
大家可以看到,如果不轉(zhuǎn)義時,那么它直接顯示除出了 <h1></h1> 標(biāo)簽。但其實我們希望的是,想要把它轉(zhuǎn)義成一級標(biāo)簽的內(nèi)容。那應(yīng)該怎么處理呢?
我們就通過 dangerouslySetInnerHTML 這個屬性來對 html 進(jìn)行設(shè)置,已達(dá)到對 <li> 標(biāo)簽下的內(nèi)容進(jìn)行改變,具體代碼如下:
<likey={index}onClick={this.handleItemDelete.bind(this, index)}dangerouslySetInnerHTML={{ __html: item }}> </li>我們來看下顯示效果:
通過對 dangerouslySetInnerHTML 的設(shè)置,我們 html 的內(nèi)容進(jìn)行了轉(zhuǎn)義。
(2)光標(biāo)聚焦
在實際的實踐中,對于 input 框來說,我們往往會想要點擊某個文本,然后讓它去聚焦到 input 框中輸入內(nèi)容。那這應(yīng)該怎么處理呢?
我們繼續(xù)來改造 jsx 代碼。具體代碼如下:
render() {return (<Fragment><div><label htmlFor="insertArea">輸入內(nèi)容</label><inputid="insertArea"className="input"value={this.state.inputValue}onChange={this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return (<likey={index}onClick={this.handleItemDelete.bind(this, index)}dangerouslySetInnerHTML={{ __html: item }}></li>)})}</ul></Fragment>)}此時瀏覽器的顯示效果為:
大家可以看到,當(dāng)我們點擊輸入內(nèi)容這四個字時,光標(biāo)就自動地聚焦到 input 框上,并且能夠進(jìn)行自由地輸入。那這樣的功能是怎么實現(xiàn)的呢?
在上面的代碼中,我們可以看到,通過 label 標(biāo)簽和 htmlFor 來對內(nèi)容進(jìn)行綁定,以達(dá)到最終我們想要實現(xiàn)的效果。
2. 拆分組件與組件之間的傳值
在實際的項目中,對于一個大的組件來說,我們總是會對其進(jìn)行組件拆分。那對于上面這個 todoList 組件來說,也不例外。
我們可以把①輸入內(nèi)容,② input 框 和 ③提交按鈕拆分成一個組件。之后呢,把 list 列表拆分成另外一個組件。那接下來我們來對這個組件進(jìn)行拆分以及父子組件間數(shù)據(jù)的傳遞。
首先我們在項目的 src 文件夾下添加一個新的文件。命名為 TodoItem.js 。具體代碼如下:
import React, { Component } from 'react';class TodoItem extends Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}render() {return (<divonClick={this.handleClick}>{this.props.content}</div>)}handleClick() {this.props.deleteItem(this.props.index);} }export default TodoItem;現(xiàn)在,我們來改造 TodoList.js 文件。具體代碼如下:
import React, { Component, Fragment } from 'react'; import './style.css'; import TodoItem from './TodoItem';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}}render() {return (<Fragment><div><label htmlFor="insertArea">輸入內(nèi)容</label><inputid="insertArea"className="input"value={this.state.inputValue}onChange={this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return (<div>{/* 父組件將content,index 和 deleteItem 將對應(yīng)的內(nèi)容傳遞給子組件 */}<TodoItemcontent={item}index={index}deleteItem={this.handleItemDelete.bind(this)}/>{/*<likey={index}onClick={this.handleItemDelete.bind(this, index)}dangerouslySetInnerHTML={{ __html: item }}></li>*/}</div>)})}</ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})// console.log(e.target.value)}handleBtnClick() {// ... 展開運算符會將之前的數(shù)組進(jìn)行展開,并生成一個全新的數(shù)組// 將input框的值和list的值進(jìn)行合并形成一個新的數(shù)組this.setState({list: [...this.state.list, this.state.inputValue],inputValue: ''})}handleItemDelete(index) {const list = [...this.state.list];list.splice(index, 1);this.setState({list: list})} }export default TodoList;就這樣,我們對組件進(jìn)行拆分,達(dá)到了與上面未拆分前一樣的效果。
那現(xiàn)在,我們來梳理下其中的知識點。主要有以下兩個知識點:
- 如何進(jìn)行組件的拆分
- 父組件向子組件傳遞值,應(yīng)該怎么傳遞
首先,我們創(chuàng)建了一個新的文件 TodoItem ,來存放列表的內(nèi)容,這是第一點。
其次,有了列表的內(nèi)容后,我們要來想,父子組件間的數(shù)據(jù),怎么傳遞。那事實上,父組件向子組件傳遞內(nèi)容,通過屬性的形式來傳遞。大家看到父組件中 <TodoItem /> 的位置,在父組件中,通過 content={item} 這樣的形式,來把 item 命名為 content ,并將其傳遞給子組件。
而對于子組件 <TodoItem /> 來說,它將以 this.props 的方式來調(diào)用父組件的數(shù)據(jù)和事件。
3. TodoList代碼優(yōu)化
在上面的代碼中,我們對組件進(jìn)行拆分,以及實現(xiàn)了父子組件間的數(shù)據(jù)傳遞。
但細(xì)心的小伙伴可能已經(jīng)發(fā)現(xiàn),代碼這么寫可能還不夠美觀。因此,我們來對這兩個組件的代碼進(jìn)行優(yōu)化。
首先是 TodoItem.js 。具體代碼如下:
import React, { Component } from 'react';class TodoItem extends Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}render() {const { content } = this.props;return (<div onClick={this.handleClick}>{/* {this.props.content} */}{content}</div>)}handleClick() {const { deleteItem, index } = this.props;deleteItem(index);} }export default TodoItem;我們把 this.props 給單獨提取出來,之后再將其放在組件當(dāng)中使用。同時呢,我們還對 this.handleClick.bind(this) 單獨提取出來,這樣也使得組件更加美觀。
其次,我們來改造 TodoList.js 。具體代碼如下:
import React, { Component, Fragment } from 'react'; import TodoItem from './TodoItem'; import './style.css';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}this.handleInputChange = this.handleInputChange.bind(this);this.handleBtnClick = this.handleBtnClick.bind(this);this.handleItemDelete = this.handleItemDelete.bind(this);}render() {return (<Fragment><div><label htmlFor="insertArea">輸入內(nèi)容</label><inputid="insertArea"className="input"value={this.state.inputValue}onChange={this.handleInputChange}/><buttononClick={this.handleBtnClick}>提交</button></div><ul>{this.getTodoItem()}</ul></Fragment>)}getTodoItem() {// 父組件將content,index 和 deleteItem 將對應(yīng)的內(nèi)容傳遞給子組件return this.state.list.map((item, index) => {return (< TodoItemkey={index}content={item}index={index}deleteItem={this.handleItemDelete}/>)})}handleInputChange(e) {const value = e.target.value;this.setState(() => ({inputValue: value}));// console.log(e.target.value)}handleBtnClick() {// prevState表示在修改數(shù)據(jù)之前數(shù)據(jù)是怎么樣的,避免不小心的改變state的狀態(tài)this.setState((prevState) => ({list: [...prevState.list, prevState.inputValue],inputValue: ''}));}handleItemDelete(index) {this.setState((prevState) => {const list = [...prevState.list];list.splice(index, 1);return { list };});} }export default TodoList;同樣地,我們先把 handleInputChange 、 handleBtnClick 、 handleItemDelete 這三個事件給抽離出來。
其次呢,我們把 this.state.list.map() 給單獨出來形成 getTodoItem() 方法,并使用 {this.getTodoItem()} 進(jìn)行調(diào)用。
最后,我們分別對事件中的 this.setState({}) 進(jìn)行升級改造,將當(dāng)前所有事件中的所有數(shù)據(jù)都封裝在一個函數(shù)內(nèi)。
🌠四、圍繞React衍生出的思考
上面我們基本完成了對 TodoList 功能的開發(fā)。那么現(xiàn)在,我們將圍繞著我們所學(xué)的,來衍生出 react 的一些番外的知識點。具體如下:
- 聲明式開發(fā) —— 以前我們在 js 的開發(fā)中,都是大量的操作 DOM ,這種開發(fā)方式稱為命令式開發(fā)。到現(xiàn)在,我們在使用 react 時,基本都是直接操作數(shù)據(jù),而不是操作 DOM 。那么這樣的開發(fā)方式,被稱為是聲明式開發(fā)。
- 可以與其他框架并存
- 組件化方式開發(fā)
- 單向數(shù)據(jù)流 —— 在 react 中,父組件允許往子組件傳值,但是子組件只能去使用這個值,而不能去改變這個值。
- 視圖層框架 —— 只幫助我們解決數(shù)據(jù)和頁面上的內(nèi)容,并不負(fù)責(zé)組件間怎么傳值,如何傳值。
- 函數(shù)式編程 —— 當(dāng)一個函數(shù)內(nèi)容變得多時,可以進(jìn)行拆分。每一個函數(shù)各司其職,使得代碼更具有維護(hù)性。同時,給前端的自動化測試帶來巨大的便捷性。
🌌五、結(jié)束語
在上面的文章中,我們學(xué)到了關(guān)于 react 的一些基礎(chǔ)知識。除此之外呢,我們還對 TodoList 進(jìn)行了基礎(chǔ)編寫和進(jìn)階操作編寫。與此同時,我們還圍繞 React 衍生出了一些思考。不知道小伙伴們是否對 react 有一些了解了呢?
??彩蛋
- 關(guān)注公眾號星期一研究室,第一時間關(guān)注優(yōu)質(zhì)文章,更有面試專欄待你解鎖~
- 如果您覺得這篇文章有幫助到您的的話不妨點贊支持一下喲~~😉
- 以上就是本文的全部內(nèi)容!我們下期見!👋👋👋
總結(jié)
以上是生活随笔為你收集整理的初探react,用react实现一个todoList功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创新视角下的复盘 | 2021/08/0
- 下一篇: react只停留在表层?五大知识点带你梳