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