React使用
- React vs Vue
- React使用
- React面試題
- React基本使用
- JSX基本使用
- 條件判斷
- 渲染列表
- 事件
- 表單
- 組件使用
- setState
- 組件生命周期
- 總結
- React高級特性
- 函數組件
- 非受控組件
- Portals
- context
- 異步組件
- 性能優化
- shouldComponentUpdate(簡稱SCU)
- SCU一定要配合不可變值
- SCU使用總結
- PureComponent和React.memo
- 不可變值immutable.js
- 性能優化-小結
- 高階組件HOC
- Renders Props
- 知識點總結
- Redux
- Redux使用
- 基本概念
- 單項數據流
- react-redux
- 異步action
- 中間件
- Redux知識總結
- React-router
React vs Vue
React和Vue一樣重要(特別是大廠面試),力求兩者都會
React和Vue有很多相通之處,而且正在趨于一致
React比Vue學習成本高,尤其對于初學者
React使用
基本使用–常用,必須會
高級特性–不常用,但體現深度
Redux和React-router使用
React面試題
React組件如何通訊
JSX本質是什么
context是什么?有何用途
shouldComponentUpdate的用途
描述redux單項數據流
setState是同步還是異步?(場景圖)
React基本使用
JSX基本使用
變量、表達式
class style
子元素和組件
import React
from 'react'
import './style.css'
import List
from '../List'class JSXBaseDemo extends React.Component {constructor(props
) {super(props
)this.state
= {name
: '雙越',imgUrl
: 'https://img1.mukewang.com/5a9fc8070001a82402060220-140-140.jpg',flag
: true}}render() {const rawHtml
= '<span>富文本內容<i>斜體</i><b>加粗</b></span>'const rawHtmlData
= {__html
: rawHtml
}const rawHtmlElem
= <div
><p dangerouslySetInnerHTML
={rawHtmlData
}></p
><p
>{rawHtml
}</p
></div
>return rawHtmlElem
}
}export default JSXBaseDemo
條件判斷
if else
三元表達式
邏輯運算符 && ||
import React
from 'react'
import './style.css'class ConditionDemo extends React.Component {constructor(props
) {super(props
)this.state
= {theme
: 'black'}}render() {const blackBtn
= <button className
="btn-black">black btn
</button
>const whiteBtn
= <button className
="btn-white">white btn
</button
>return <div
>{ this.state
.theme
=== 'black' && blackBtn
}</div
>}
}export default ConditionDemo
渲染列表
map:map返回一個重組數組
key
import React
from 'react'class ListDemo extends React.Component {constructor(props
) {super(props
)this.state
= {list
: [{id
: 'id-1',title
: '標題1'},{id
: 'id-2',title
: '標題2'},{id
: 'id-3',title
: '標題3'}]}}render() {return <ul
>{ this.state
.list
.map((item
, index
) => {return <li key
={item
.id
}>index
{index
}; id
{item
.id
}; title
{item
.title
}</li
>})}</ul
>}
}export default ListDemo
事件
bind this
關于event參數
傳遞自定義參數
import React
from 'react'class EventDemo extends React.Component {constructor(props
) {super(props
)this.state
= {name
: 'zhangsan',list
: [{id
: 'id-1',title
: '標題1'},{id
: 'id-2',title
: '標題2'},{id
: 'id-3',title
: '標題3'}]}this.clickHandler1
= this.clickHandler1
.bind(this)}render() {return <ul
>{this.state
.list
.map((item
, index
) => {return <li key
={item
.id
} onClick
={this.clickHandler4
.bind(this, item
.id
, item
.title
)}>index
{index
}; title
{item
.title
}</li
>})}</ul
>}clickHandler1() {this.setState({name
: 'lisi'})}clickHandler2 = () => {this.setState({name
: 'lisi'})}clickHandler3 = (event
) => {event
.preventDefault() event
.stopPropagation() console
.log('target', event
.target
) console
.log('current target', event
.currentTarget
) console
.log('event', event
) console
.log('event.__proto__.constructor', event
.__proto__
.constructor
)console
.log('nativeEvent', event
.nativeEvent
)console
.log('nativeEvent target', event
.nativeEvent
.target
) console
.log('nativeEvent current target', event
.nativeEvent
.currentTarget
) }clickHandler4(id
, title
, event
) {console
.log(id
, title
)console
.log('event', event
) }
}export default EventDemo
表單
受控組件:input的值受state影響
input textarea select 用valuei
checkbox radio 用 checked
import React
from 'react'class FormDemo extends React.Component {constructor(props
) {super(props
)this.state
= {name
: '雙越',info
: '個人信息',city
: 'beijing',flag
: true,gender
: 'male'}}render() {return <div
><textarea value
={this.state
.info
} onChange
={this.onTextareaChange
}/><p
>{this.state
.info
}</p
></div
>}onInputChange = (e
) => {this.setState({name
: e
.target
.value
})}onTextareaChange = (e
) => {this.setState({info
: e
.target
.value
})}onSelectChange = (e
) => {this.setState({city
: e
.target
.value
})}onCheckboxChange = () => {this.setState({flag
: !this.state
.flag
})}onRadioChange = (e
) => {this.setState({gender
: e
.target
.value
})}
}export default FormDemo
組件使用
props傳遞數據
props傳遞函數
props類型檢查
import React
from 'react'
import PropTypes
from 'prop-types'class Input extends React.Component {constructor(props
) {super(props
)this.state
= {title
: ''}}render() {return <div
><input value
={this.state
.title
} onChange
={this.onTitleChange
}/><button onClick
={this.onSubmit
}>提交
</button
></div
>}onTitleChange = (e
) => {this.setState({title
: e
.target
.value
})}onSubmit = () => {const { submitTitle
} = this.props
submitTitle(this.state
.title
) this.setState({title
: ''})}
}
Input
.propTypes
= {submitTitle
: PropTypes
.func
.isRequired
}class List extends React.Component {constructor(props
) {super(props
)}render() {const { list
} = this.props
return <ul
>{list
.map((item
, index
) => {return <li key
={item
.id
}><span
>{item
.title
}</span
></li
>})}</ul
>}
}
List
.propTypes
= {list
: PropTypes
.arrayOf(PropTypes
.object
).isRequired
}class Footer extends React.Component {constructor(props
) {super(props
)}render() {return <p
>{this.props
.text
}{this.props
.length
}</p
>}componentDidUpdate() {console
.log('footer did update')}shouldComponentUpdate(nextProps
, nextState
) {if (nextProps
.text
!== this.props
.text
|| nextProps
.length
!== this.props
.length
) {return true }return false }
}class TodoListDemo extends React.Component {constructor(props
) {super(props
)this.state
= {list
: [{id
: 'id-1',title
: '標題1'},{id
: 'id-2',title
: '標題2'},{id
: 'id-3',title
: '標題3'}],footerInfo
: '底部文字'}}render() {return <div
><Input submitTitle
={this.onSubmitTitle
}/><List list
={this.state
.list
}/><Footer text
={this.state
.footerInfo
} length
={this.state
.list
.length
}/></div
>}onSubmitTitle = (title
) => {this.setState({list
: this.state
.list
.concat({id
: `id-${Date.now()}`,title
})})}
}export default TodoListDemo
setState
不可變值(setstate不能提前對state值進行修改,應該什么時候改就什么時候設值,而且設置的時候不能影響之前state的值)
可能是異步更新
可能會被合并
import React
from 'react'class ListDemo extends React.Component {constructor(props
) {super(props
)this.state
= {count
: 0}}render() {return <p
>{this.state
.count
}</p
>}componentDidMount() {this.setState({ count
: this.state
.count
+ 1 })console
.log('1', this.state
.count
) this.setState({ count
: this.state
.count
+ 1 })console
.log('2', this.state
.count
) setTimeout(() => {this.setState({ count
: this.state
.count
+ 1 })console
.log('3', this.state
.count
) })setTimeout(() => {this.setState({ count
: this.state
.count
+ 1 })console
.log('4', this.state
.count
) })}
}export default ListDemo
import React
from 'react'
class StateDemo extends React.Component {constructor(props
) {super(props
)this.state
= {count
: 0}}render() {return <div
><p
>{this.state
.count
}</p
><button onClick
={this.increase
}>累加
</button
></div
>}increase = () => {this.setState((prevState
, props
) => {return {count
: prevState
.count
+ 1}})this.setState((prevState
, props
) => {return {count
: prevState
.count
+ 1}})this.setState((prevState
, props
) => {return {count
: prevState
.count
+ 1}})}
}export default StateDemo
組件生命周期
單組件生命周期
// React 組件生命周期圖示
// http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
父子組件生命周期,和Vue的一樣
總結
JSX基本使用
條件
列表
事件
表單
組件和props
setState
生命周期
React高級特性
不是每個都很常用,但用到的時候必須要知道
考察候選人對React的掌握是否全面,且有深度
考察做過的項目是否有深度和復雜度(至少能用到高級特性)
函數組件
純函數,輸入props,輸出JSX
沒有實例,沒有生命周期,沒有state
不能擴展其他方法
非受控組件
ref
defaultValue defaultChecked
手動操作DOM元素
import React
from 'react'class App extends React.Component {constructor(props
) {super(props
)this.state
= {name
: '雙越',flag
: true,}this.nameInputRef
= React
.createRef() this.fileInputRef
= React
.createRef()}render() {return <div
><input type
="file" ref
={this.fileInputRef
}/><button onClick
={this.alertFile
}>alert file
</button
></div
>}alertName = () => {const elem
= this.nameInputRef
.current
alert(elem
.value
) }alertFile = () => {const elem
= this.fileInputRef
.current
alert(elem
.files
[0].name
)}
}export default App
使用場景
必須手動操作DOM元素,setState實現不了
文件上傳
某些富文本編輯器,需要傳入DOM元素
受控組件 vs 非受控組件
優先使用受控組件,符合React設計原則
必須操作DOM時,再使用非受控組件
Portals
組件默認會按照既定層次嵌套渲染
如何讓組件渲染到父組件以外
import React
from 'react'
import ReactDOM
from 'react-dom'
import './style.css'class App extends React.Component {constructor(props
) {super(props
)this.state
= {}}render() {return ReactDOM
.createPortal(<div className
="modal">{this.props
.children
}</div
>,document
.body
)}
}export default App
使用場景
overflow:hidden
父組件z-index值太小
fixed需要放在body第一層級
context
公共信息(語言、主題)如何傳遞給每個組件
用props太繁瑣
用redux小題大做
import React
from 'react'
const ThemeContext
= React
.createContext('light')
function ThemeLink (props
) {return <ThemeContext
.Consumer
>{ value
=> <p
>link's theme is
{value
}</p
> }</ThemeContext
.Consumer
>
}
class ThemedButton extends React.Component {render() {const theme
= this.context
return <div
><p
>button's theme is
{theme
}</p
></div
>}
}
ThemedButton
.contextType
= ThemeContext
function Toolbar(props
) {return (<div
><ThemedButton
/><ThemeLink
/></div
>)
}class App extends React.Component {constructor(props
) {super(props
)this.state
= {theme
: 'light'}}render() {return <ThemeContext
.Provider value
={this.state
.theme
}><Toolbar
/><hr
/><button onClick
={this.changeTheme
}>change theme
</button
></ThemeContext
.Provider
>}changeTheme = () => {this.setState({theme
: this.state
.theme
=== 'light' ? 'dark' : 'light'})}
}export default App
異步組件
import()
React.lazy
React.Suspense
import React
from 'react'const ContextDemo
= React
.lazy(() => import('./ContextDemo'))class App extends React.Component {constructor(props
) {super(props
)}render() {return <div
><p
>引入一個動態組件
</p
><hr
/><React
.Suspense fallback
={<div
>Loading
...</div
>}><ContextDemo
/></React
.Suspense
></div
>}
}export default App
強制刷新,可看到 loading (看不到就限制一下 chrome 網速)
看 network 的 js 加載,會單獨有個js
性能優化
性能優化,永遠都是面試的重點
性能優化對于React更加重要
回顧講setState時重點強調的不可變值
shouldComponentUpdate(簡稱SCU)
React默認:父組件有更新,子組件無論數據是否改變則無條件也更新
SCU默認返回true
import React
from 'react'
import PropTypes
from 'prop-types'class Input extends React.Component {constructor(props
) {super(props
)this.state
= {title
: ''}}render() {return <div
><input value
={this.state
.title
} onChange
={this.onTitleChange
}/><button onClick
={this.onSubmit
}>提交
</button
></div
>}onTitleChange = (e
) => {this.setState({title
: e
.target
.value
})}onSubmit = () => {const { submitTitle
} = this.props
submitTitle(this.state
.title
) this.setState({title
: ''})}
}
Input
.propTypes
= {submitTitle
: PropTypes
.func
.isRequired
}class List extends React.Component {constructor(props
) {super(props
)}render() {const { list
} = this.props
return <ul
>{list
.map((item
, index
) => {return <li key
={item
.id
}><span
>{item
.title
}</span
></li
>})}</ul
>}
}
List
.propTypes
= {list
: PropTypes
.arrayOf(PropTypes
.object
).isRequired
}class Footer extends React.Component {constructor(props
) {super(props
)}render() {return <p
>{this.props
.text
}{this.props
.length
}</p
>}componentDidUpdate() {console
.log('footer did update')}shouldComponentUpdate(nextProps
, nextState
) {if (nextProps
.text
!== this.props
.text
|| nextProps
.length
!== this.props
.length
) {return true }return false }
}class TodoListDemo extends React.Component {constructor(props
) {super(props
)this.state
= {list
: [{id
: 'id-1',title
: '標題1'},{id
: 'id-2',title
: '標題2'},{id
: 'id-3',title
: '標題3'}],footerInfo
: '底部文字'}}render() {return <div
><Input submitTitle
={this.onSubmitTitle
}/><List list
={this.state
.list
}/><Footer text
={this.state
.footerInfo
} length
={this.state
.list
.length
}/></div
>}onSubmitTitle = (title
) => {this.setState({list
: this.state
.list
.concat({id
: `id-${Date.now()}`,title
})})}
}export default TodoListDemo
SCU一定要配合不可變值
import React
from 'react'
import PropTypes
from 'prop-types'
import _
from 'lodash'class Input extends React.Component {constructor(props
) {super(props
)this.state
= {title
: ''}}render() {return <div
><input value
={this.state
.title
} onChange
={this.onTitleChange
}/><button onClick
={this.onSubmit
}>提交
</button
></div
>}onTitleChange = (e
) => {this.setState({title
: e
.target
.value
})}onSubmit = () => {const { submitTitle
} = this.props
submitTitle(this.state
.title
)this.setState({title
: ''})}
}
Input
.propTypes
= {submitTitle
: PropTypes
.func
.isRequired
}class List extends React.Component {constructor(props
) {super(props
)}render() {const { list
} = this.props
return <ul
>{list
.map((item
, index
) => {return <li key
={item
.id
}><span
>{item
.title
}</span
></li
>})}</ul
>}shouldComponentUpdate(nextProps
, nextState
) {if (_
.isEqual(nextProps
.list
, this.props
.list
)) {return false}return true }
}
List
.propTypes
= {list
: PropTypes
.arrayOf(PropTypes
.object
).isRequired
}class TodoListDemo extends React.Component {constructor(props
) {super(props
)this.state
= {list
: [{id
: 'id-1',title
: '標題1'},{id
: 'id-2',title
: '標題2'},{id
: 'id-3',title
: '標題3'}]}}render() {return <div
><Input submitTitle
={this.onSubmitTitle
}/><List list
={this.state
.list
}/></div
>}onSubmitTitle = (title
) => {this.setState({list
: this.state
.list
.concat({id
: `id-${Date.now()}`,title
})})}
}export default TodoListDemo
SCU使用總結
SCU默認返回true,即React默認重新渲染所有子組件
必須配合“不可變值”一起使用
可先不用SCU,有性能問題時再考慮使用
PureComponent和React.memo
PureComponent,SCU中實現了淺比較
memo,函數組件中的PureComponent
淺比較已適用大部分情況(盡量不要深度比較)
import React
from 'react'
import PropTypes
from 'prop-types'class Input extends React.Component {constructor(props
) {super(props
)this.state
= {title
: ''}}render() {return <div
><input value
={this.state
.title
} onChange
={this.onTitleChange
}/><button onClick
={this.onSubmit
}>提交
</button
></div
>}onTitleChange = (e
) => {this.setState({title
: e
.target
.value
})}onSubmit = () => {const { submitTitle
} = this.props
submitTitle(this.state
.title
)this.setState({title
: ''})}
}
Input
.propTypes
= {submitTitle
: PropTypes
.func
.isRequired
}class List extends React.PureComponent {constructor(props
) {super(props
)}render() {const { list
} = this.props
return <ul
>{list
.map((item
, index
) => {return <li key
={item
.id
}><span
>{item
.title
}</span
></li
>})}</ul
>}shouldComponentUpdate() {}
}
List
.propTypes
= {list
: PropTypes
.arrayOf(PropTypes
.object
).isRequired
}class TodoListDemo extends React.Component {constructor(props
) {super(props
)this.state
= {list
: [{id
: 'id-1',title
: '標題1'},{id
: 'id-2',title
: '標題2'},{id
: 'id-3',title
: '標題3'}]}}render() {return <div
><Input submitTitle
={this.onSubmitTitle
}/><List list
={this.state
.list
}/></div
>}onSubmitTitle = (title
) => {this.setState({list
: this.state
.list
.concat({id
: `id-${Date.now()}`,title
})})}
}export default TodoListDemo
不可變值immutable.js
徹底擁抱“不可變值”
基于共享數據(不是深拷貝),速度好
有一定學習和遷移成本,按需使用
性能優化-小結
面試重點,且涉及React涉及理念
SCU PureComponent memo immutable.js
按需使用 & state層級
高階組件HOC
關于組件公共邏輯的抽離
mixin,已被React棄用
高階組件HOC
Render Props
import React
from 'react'
const withMouse = (Component
) => {class withMouseComponent extends React.Component {constructor(props
) {super(props
)this.state
= { x
: 0, y
: 0 }}handleMouseMove = (event
) => {this.setState({x
: event
.clientX
,y
: event
.clientY
})}render() {return (<div style
={{ height
: '500px' }} onMouseMove
={this.handleMouseMove
}>{}<Component
{...this.props
} mouse
={this.state
}/></div
>)}}return withMouseComponent
}const App = (props
) => {const a
= props
.a
const { x
, y
} = props
.mouse
return (<div style
={{ height
: '500px' }}><h1
>The mouse position
is ({x
}, {y
})</h1
><p
>{a
}</p
></div
>)
}export default withMouse(App
)
connect源碼
提問:Vue如何實現高階組件?
Renders Props
import React
from 'react'
import PropTypes
from 'prop-types'class Mouse extends React.Component {constructor(props
) {super(props
)this.state
= { x
: 0, y
: 0 }}handleMouseMove = (event
) => {this.setState({x
: event
.clientX
,y
: event
.clientY
})}render() {return (<div style
={{ height
: '500px' }} onMouseMove
={this.handleMouseMove
}>{}{this.props
.render(this.state
)}</div
>)}
}
Mouse
.propTypes
= {render
: PropTypes
.func
.isRequired
}const App = (props
) => (<div style
={{ height
: '500px' }}><p
>{props
.a
}</p
><Mouse render
={({ x
, y
}) => <h1
>The mouse position
is ({x
}, {y
})</h1
>}/></div
>
)export default App
HOC vs Render Props
HOC:模式簡單,但會增加組件層級
Render Props:代碼簡潔,學習成本較高
按需使用
知識點總結
函數組件
非受控組件
Portals
context
異步組件
性能優化(重要)
高階組件HOC
Render Props
Redux
和Vuex作用相同,但比Vuex學習成本高
不可變值,純函數
面試常考
Redux使用
基本概念
store state
action
reducer
import { createStore
} from 'redux';
function counter(state
= 0, action
) {switch (action
.type
) {case 'INCREMENT':return state
+ 1;case 'DECREMENT':return state
- 1;default:return state
;}
}
let store
= createStore(counter
);
store
.subscribe(() =>console
.log(store
.getState())
);
store
.dispatch({ type
: 'INCREMENT' });
store
.dispatch({ type
: 'INCREMENT' });
store
.dispatch({ type
: 'DECREMENT' });
單項數據流
dispatch(action)
reducer -> newState
subscribe觸發通知
dispatch一個action會觸發reducer,reducer更新狀態,注意不可變值,再觸發訂閱通知,渲染到頁面
react-redux
Provider
connect
mapStateToProps mapDispatchToProps
import React
from 'react'
import { Provider
} from 'react-redux'
import { createStore
} from 'redux'
import todoApp
from './reducers'
import App
from './components/App'let store
= createStore(todoApp
)export default function () {return <Provider store
={store
}><App
/></Provider
>
}
import React
from 'react'
import { connect
} from 'react-redux'
import { addTodo
} from '../actions'
let AddTodo = ({ dispatch
}) => {let input
return (<div
><formonSubmit
={e
=> {e
.preventDefault()if (!input
.value
.trim()) {return}dispatch(addTodo(input
.value
))input
.value
= ''}}><inputref
={node
=> {input
= node
}}/><button type
="submit">Add Todo
</button
></form
></div
>)
}
AddTodo
= connect()(AddTodo
)export default AddTodo
import { connect
} from 'react-redux'
import { toggleTodo
} from '../actions'
import TodoList
from '../components/TodoList'
const getVisibleTodos = (todos
, filter
) => {switch (filter
) {case 'SHOW_ALL':return todos
case 'SHOW_COMPLETED':return todos
.filter(t
=> t
.completed
)case 'SHOW_ACTIVE':return todos
.filter(t
=> !t
.completed
)}
}const mapStateToProps = state
=> {return {todos
: getVisibleTodos(state
.todos
, state
.visibilityFilter
)}
}const mapDispatchToProps = dispatch
=> {return {onTodoClick
: id
=> {dispatch(toggleTodo(id
))}}
}
const VisibleTodoList
= connect(mapStateToProps
,mapDispatchToProps
)(TodoList
)export default VisibleTodoList
異步action
異步action使用前要引入中間件
中間件有:
redux-thunk
redux-promise
redux-saga
中間件
Redux知識總結
基本概念
單項數據流
react-redux
異步action
中間件
React-router
面試考點并不多(前提是熟悉React)
路由模式(hash,H5 history),同vue-router
路由配置(動態路由、懶加載),同vue-router
路由模式
hash模式(默認),如http://abc.com/#/user/10
H5 history模式,如http://abc.com/user/20
后者需要server端支持,因此無特殊需求可選擇前者
toC客戶端一般H5 history,toB控制后臺一般hash
React-router總結
路由模式(hash、H5 history)
路由配置(動態路由、懶加載)
掌握基本使用
總結
以上是生活随笔為你收集整理的(七)React使用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。