初探react,用react實作一個todoList功能
- 🛰?前言
- 🚀一、react基礎
- 1. react簡介
- 2. 開發環境搭建
- 3. 工程目錄檔案簡介
- 4. react中最基礎的JSX語法
- 🛸二、使用react撰寫TodoList功能
- 1. 頁面構思
- 2. React中的回應式設計思想和事件系結
- 3. 實作TodoList新增洗掉功能
- (1)新增功能
- (2)洗掉功能
- 🪐三、對TodoList功能進行進階操作
- 1. JSX語法細節補充
- (1)自動轉義
- (2)游標聚焦
- 2. 拆分組件與組件之間的傳值
- 3. TodoList代碼優化
- 🌠四、圍繞React衍生出的思考
- 🌌五、結束語
- ??彩蛋
🛰?前言
對于前端而言, react 是前端三大主流框架之一,而在現實生產中,基本上很多大型公司也會偏向于使用 react ,原因在于 react 的 diy 能力比起其他框架也會稍微要更好一些~
緊跟著新技術的步伐,周一也開始學期了 react ,那在下面的文章中,將講解關于 react 的一些基礎知識點,同時呢,也將用 react 來實作一個 TodoList 的功能,
叮咚,開始奇妙的 eract 之旅~🚋
🚀一、react基礎
在對 todoList 功能進行設計之前,我們先來了解一點 react 相關的基礎知識,
1. react簡介
對于 reactjs 來說,需要了解的一些基礎知識主要有以下幾點:
reactjs→react native→react VR;- 由
Facebook推出的一款框架,于2013年開源于社區; react擁有豐富的函式式編程;react目前在全球范圍內,是使用人數最多的前端框架,同時它擁有健全的檔案與完善的社區;React Fiber是React 16的版本,它為React做了很多底層的優化,
2. 開發環境搭建
在進入 react 的基礎學習之前,我們首先來搭建 react 的開發環境,對于 react 的環境搭建來說,一般有兩種方式,分別是:
- 通過引入
.js檔案來使用React; - 通過腳手架工具來編碼,比如
GRUNT、Gulp和webpack; - 使用
create-react-app來搭建環境,
那么現在,我們用 create-react-app 來搭建一個 react 專案,具體命令列如下:
npx create-react-app my-app
cd my-app
npm start
3. 工程目錄檔案簡介
初始化完一個專案后,我們來了解下 react 的專案結構,具體如下:
├── public
├── favicon.ico 網頁icon
├── index.html 首頁的html模板
├── manifest.json 快取檔案
├── src
├── App.css
├── App.js 填寫組件的內容
├── App.test.js 自動化測驗檔案
├── index.css
├── index.js 整個程式運行的入口檔案
├── logo.svg
├── registerServiceWorker 借助網頁寫手機app的功能
├── README.md 專案的說明檔案
├── yarn.lock 專案依賴安裝包的一些版本號
4. react中最基礎的JSX語法
以前我們在寫像 <div></div> 這種類似的語法時,一般都是寫在 HTML 檔案里面,那么,在 react 中,像 <div></div> 這種型別的代碼,是在 JS 中去寫的,因此,在 js 中寫的 html 代碼,被稱之為 jsx 語法,
值得注意的是,在 react 中使用自己定義的組件時,組件名必須以大寫為開頭,小寫開頭在 jsx 中是不支持的,這一點需要稍微注意一下,
所以,一般看到以大寫為開頭時,比如 <App /> ,則說明是我們自己定義的組件,如果是小寫為開頭時,則一般是原始的 HTML5 標簽,如 <div></div> ,
🛸二、使用react撰寫TodoList功能
1. 頁面構思
首先,我們需要先來對頁面的內容進行構造,我們在專案的 src檔案夾下創建一個檔案,命名為 TodoList ,具體代碼如下:
import React, { Component, Fragment } from 'react';
class TodoList extends Component {
render() {
return (
<Fragment>
<div>
<input />
<button></button>
</div>
<ul>
<li>學英語</li>
<li>Learning React</li>
</ul>
</Fragment>
)
}
}
export default TodoList;
此時瀏覽器的顯示效果如下:

2. React中的回應式設計思想和事件系結
上面我們簡單了顯示了 todolist 的基本功能,那現在,我們想要實作的是,點擊提交按鈕,可以把 input 框里面的內容顯示在串列下方,這又該怎么處理呢?
如果按照我們正常的思維來想的話,我們可能會覺得,在提交按鈕中系結一個事件,之后呢,當點擊系結按鈕時,獲取到 input 框的值,進行系結提交,
但事實上, react 強調的是,我們不要直接操作 DOM ,而是要操作資料,當資料發生變化時, react 會自動地感知到我們資料發生的變化,會自動地幫我們生成 DOM ,
因此,在寫 react 時,我們不需要關心 DOM 層面的操作,只需要去關心資料層面的操作即可,
現在,我們先來監聽 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>學英語</li>
<li>Learning React</li>
</ul>
</Fragment>
)
}
handleInputChange(e) {
this.setState({
inputValue: e.target.value
})
}
}
export default TodoList;
此時瀏覽器的列印效果為:

大家可以看到,我們正確的使得 input 框回應到了資料,
那在上面的這段代碼中,需要了解的知識點有以下幾點,分別是:
state負責存盤組件中的資料;- 如果想要在
html代碼中用一些js的運算式,那么要記得用{}進行包裹; - 在進行事件系結時,記得使用
bind(this)對事件的作用域進行變更; - 當你想要改變資料項時,不能直接使用
this.state來改變資料的值,要通過setState函式來進行改變,
3. 實作TodoList新增洗掉功能
(1)新增功能
在上面的例子中,我們實作了 input 框中值的獲取,那現在,我們要來實作點擊提交這個按鈕,能夠實作對 input 框中值的新增,同樣地,是在 TodoList.js 檔案下進行修改,具體代碼如下:
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() {
// ... 展開運算子會將之前的陣列進行展開,并生成一個全新的陣列
// 將input框的值和list的值進行合并形成一個新的陣列
this.setState({
list: [...this.state.list, this.state.inputValue],
inputValue: ''
})
}
}
export default TodoList;
此時瀏覽器的顯示效果如下:

在上面的代碼中,需要了解的知識點有:
- 我們先在
button中系結了handleBtnClick事件; - 之后通過展開運算子
...,將陣列的內容給合并到list陣列中; - 最后,使用
js中的map()方法,將陣列串列中的內容給遍歷出來,
(2)洗掉功能
繼續,我們來實作洗掉功能,具體代碼如下:
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}
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> 標簽下系結了 handleItemDelete 事件,之后呢,通過傳遞它的 id 值 index ,同時,配合 splice() 方法,來洗掉掉掉 list 中具體的內容,
值得注意的是,在 react 中,它是不允許我們對 state 做任何改變的,比如說,我們想要把上面洗掉代碼的邏輯這么寫:
handleItemDelete(index) {
this.state.list.splice(index, 1);
this.setState({
list: this.state.list
})
}
如果我們直接去操作 this 來改變最后的結果,這會使得函式變得很難用,同時,這種方式在 react 中也是不允許滴!這是應該注意的一個點!
🪐三、對TodoList功能進行進階操作
1. JSX語法細節補充
(1)自動轉義
如果在 jsx 中,我們希望顯示一些內容,且這些內容我們希望它自動轉義,像下圖這樣:

大家可以看到,如果不轉義時,那么它直接顯示除出了 <h1></h1> 標簽,但其實我們希望的是,想要把它轉義成一級標簽的內容,那應該怎么處理呢?
我們就通過 dangerouslySetInnerHTML 這個屬性來對 html 進行設定,已達到對 <li> 標簽下的內容進行改變,具體代碼如下:
<li
key={index}
onClick={this.handleItemDelete.bind(this, index)}
dangerouslySetInnerHTML={{ __html: item }}
>
</li>
我們來看下顯示效果:

通過對 dangerouslySetInnerHTML 的設定,我們 html 的內容進行了轉義,
(2)游標聚焦
在實際的實踐中,對于 input 框來說,我們往往會想要點擊某個文本,然后讓它去聚焦到 input 框中輸入內容,那這應該怎么處理呢?
我們繼續來改造 jsx 代碼,具體代碼如下:
render() {
return (
<Fragment>
<div>
<label htmlFor="insertArea">輸入內容</label>
<input
id="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 (
<li
key={index}
onClick={this.handleItemDelete.bind(this, index)}
dangerouslySetInnerHTML={{ __html: item }}
>
</li>
)
})
}
</ul>
</Fragment>
)
}
此時瀏覽器的顯示效果為:

大家可以看到,當我們點擊輸入內容這四個字時,游標就自動地聚焦到 input 框上,并且能夠進行自由地輸入,那這樣的功能是怎么實作的呢?
在上面的代碼中,我們可以看到,通過 label 標簽和 htmlFor 來對內容進行系結,以達到最終我們想要實作的效果,
2. 拆分組件與組件之間的傳值
在實際的專案中,對于一個大的組件來說,我們總是會對其進行組件拆分,那對于上面這個 todoList 組件來說,也不例外,
我們可以把①輸入內容,② input 框 和 ③提交按鈕拆分成一個組件,之后呢,把 list 串列拆分成另外一個組件,那接下來我們來對這個組件進行拆分以及父子組件間資料的傳遞,
首先我們在專案的 src 檔案夾下添加一個新的檔案,命名為 TodoItem.js ,具體代碼如下:
import React, { Component } from 'react';
class TodoItem extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div
onClick={this.handleClick}>
{this.props.content}
</div>
)
}
handleClick() {
this.props.deleteItem(this.props.index);
}
}
export default TodoItem;
現在,我們來改造 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">輸入內容</label>
<input
id="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 將對應的內容傳遞給子組件 */}
<TodoItem
content={item}
index={index}
deleteItem={this.handleItemDelete.bind(this)}
/>
{/*<li
key={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() {
// ... 展開運算子會將之前的陣列進行展開,并生成一個全新的陣列
// 將input框的值和list的值進行合并形成一個新的陣列
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;
就這樣,我們對組件進行拆分,達到了與上面未拆分前一樣的效果,
那現在,我們來梳理下其中的知識點,主要有以下兩個知識點:
- 如何進行組件的拆分
- 父組件向子組件傳遞值,應該怎么傳遞
首先,我們創建了一個新的檔案 TodoItem ,來存放串列的內容,這是第一點,
其次,有了串列的內容后,我們要來想,父子組件間的資料,怎么傳遞,那事實上,父組件向子組件傳遞內容,通過屬性的形式來傳遞,大家看到父組件中 <TodoItem /> 的位置,在父組件中,通過 content={item} 這樣的形式,來把 item 命名為 content ,并將其傳遞給子組件,
而對于子組件 <TodoItem /> 來說,它將以 this.props 的方式來呼叫父組件的資料和事件,
3. TodoList代碼優化
在上面的代碼中,我們對組件進行拆分,以及實作了父子組件間的資料傳遞,
但細心的小伙伴可能已經發現,代碼這么寫可能還不夠美觀,因此,我們來對這兩個組件的代碼進行優化,
首先是 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 給單獨提取出來,之后再將其放在組件當中使用,同時呢,我們還對 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">輸入內容</label>
<input
id="insertArea"
className="input"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<button
onClick={this.handleBtnClick}
>
提交
</button>
</div>
<ul>
{this.getTodoItem()}
</ul>
</Fragment>
)
}
getTodoItem() {
// 父組件將content,index 和 deleteItem 將對應的內容傳遞給子組件
return this.state.list.map((item, index) => {
return (
< TodoItem
key={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表示在修改資料之前資料是怎么樣的,避免不小心的改變state的狀態
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()} 進行呼叫,
最后,我們分別對事件中的 this.setState({}) 進行升級改造,將當前所有事件中的所有資料都封裝在一個函式內,
🌠四、圍繞React衍生出的思考
上面我們基本完成了對 TodoList 功能的開發,那么現在,我們將圍繞著我們所學的,來衍生出 react 的一些番外的知識點,具體如下:
- 宣告式開發 —— 以前我們在
js的開發中,都是大量的操作DOM,這種開發方式稱為命令式開發,到現在,我們在使用react時,基本都是直接操作資料,而不是操作DOM,那么這樣的開發方式,被稱為是宣告式開發, - 可以與其他框架并存
- 組件化方式開發
- 單向資料流 —— 在
react中,父組件允許往子組件傳值,但是子組件只能去使用這個值,而不能去改變這個值, - 視圖層框架 —— 只幫助我們解決資料和頁面上的內容,并不負責組件間怎么傳值,如何傳值,
- 函式式編程 —— 當一個函式內容變得多時,可以進行拆分,每一個函式各司其職,使得代碼更具有維護性,同時,給前端的自動化測驗帶來巨大的便捷性,
🌌五、結束語
在上面的文章中,我們學到了關于 react 的一些基礎知識,除此之外呢,我們還對 TodoList 進行了基礎撰寫和進階操作撰寫,與此同時,我們還圍繞 React 衍生出了一些思考,不知道小伙伴們是否對 react 有一些了解了呢?
??彩蛋
- 關注公眾號星期一研究室,第一時間關注優質文章,更有面試專欄待你解鎖~
- 如果您覺得這篇文章有幫助到您的的話不妨點贊支持一下喲~~😉
- 以上就是本文的全部內容!我們下期見!👋👋👋
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/310697.html
標籤:其他
