第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)
第四章:React脚手架应用(创建脚手架、代理配置、ajax相关、组件通信)(四)
第五章:react-router5路由相关一(路由相关概念、基本使用、NavLink与NavLink的封装、Switch的使用、严格匹配、路由重定向、路由组件与一般组件的区别)(五)
第六章:react-router5路由相关二(嵌套路由、路由传参、replace、编程式路由导航、withRouter的使用、BrowserRouter与HashRouter的区别)(六)
第七章:React-Router6路由相关一(路由的基本使用、重定向、NavLink·、路由表、嵌套路由)(七)
第八章:React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)
第九章:React相关扩展一(setState、lazyLoad、Hooks相关)(九)
为了简化代码,以下代码片段,除了有新的库需要引入会特意说明,其他引入react相关库的操作不再重复说明
onXxx
属性指定事件处理函数(注意大小写)
event.target
得到发生事件的DOM元素对象(触发事件的对象就是你当前需要获取的对象) ————不要过度使用ref
代码片段:
<body>
<div id="test">div>
<script type="text/javascript" src="../js/react.development.js">script>
<script type="text/javascript" src="../js/react-dom.development.js">script>
<script type="text/javascript" src="../js/babel.min.js">script>
<script type="text/babel">
class Demo extends React.Component {
myRef = React.createRef();
myRef2 = React.createRef()
showData = () => {
// console.log(this.myRef)
alert(this.myRef.current.value)
}
showData2 = (event) => {
alert(event.target.value)
}
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
<button ref='btn' onClick={this.showData}>点我提示左侧数据</button>
<input type="text" placeholder="失去焦点提示数据" onBlur={this.showData2} />
</div>
)
}
}
ReactDOM.render(<Demo />, document.getElementById('test'));
script>
body>
html>
运行结果:
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以使用 ref 来从 DOM 节点中获取表单数据。在非受控组件中,你经常希望 React 能赋予组件一个初始值, 但是不去控制后续的更新。 在这种情况下,你可以指定一个 defaultValue 属性,而不是value。
简单的话说就是:仅仅获取用户输入得值,不绑定给state,现用现取
代码片段:
<body>
<div id="test">div>
<script type="text/babel">
//创建组件
class Login extends React.Component{
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this
alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
}
render(){
return(
<form onSubmit={this.handleSubmit}>
用户名:<input ref={c => this.username = c} type="text" name="username"/>
密码:<input ref={c => this.password = c} type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
script>
body>
html>
在 HTML 中,表单元素(如 、
和
)通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
简单的话说就是:保存或者修改操作,绑定给state
代码片段:
<body>
<div id="test">div>
<script type="text/babel">
//创建组件
class Login extends React.Component{
//初始化状态
state = {
username:'', //用户名
password:'' //密码
}
//保存用户名到状态中
saveUsername = (event)=>{
this.setState({username:event.target.value})
}
//保存密码到状态中
savePassword = (event)=>{
this.setState({password:event.target.value})
}
//表单提交的回调
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render(){
return(
<form onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username"/>
密码:<input onChange={this.savePassword} type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
script>
body>
html>
高阶函数: 如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
若A函数,接收的参数是一个函数
,那么A就可以称之为高阶函数。
若A函数,调用的返回值依然是一个函数
,那么A就可以称之为高阶函数。
常见的高阶函数有: Promise、setTimeout、arr.map()等等
函数的柯里化: 通过函数调用继续返回函数
的方式,实现多次接收参数最后统一处理的函数编码形式。
function sum(a){
return(b)=>{
return (c)=>{
return a+b+c
}
}
}
代码片段:
<body>
<div id="test">div>
<script type="text/babel">
//创建组件
class Login extends React.Component{
//初始化状态
state = {
username:'', //用户名
password:'' //密码
}
//保存表单数据到状态中
saveFormData = (dataType)=>{
return (event)=>{
this.setState({[dataType]:event.target.value})
}
}
//表单提交的回调
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render(){
return(
<form onSubmit={this.handleSubmit}>
//如果传递参数,此处会直接调用函数,onChange会被赋值成当前函数的返回值
用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
script>
body>
html>
代码片段:
<body>
<div id="test">div>
<script type="text/babel">
//创建组件
class Login extends React.Component{
//初始化状态
state = {
username:'', //用户名
password:'' //密码
}
//保存表单数据到状态中
saveFormData = (dataType,event)=>{
this.setState({[dataType]:event.target.value})
}
//表单提交的回调
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render(){
return(
<form onSubmit={this.handleSubmit}>
//使用箭头函数
用户名:<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
密码:<input onChange={event => this.saveFormData('password',event) } type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
script>
body>
html>
运行结果:
1.组件从创建到死亡它会经历一些特定的阶段。
2.React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用
。
3.我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
constructor()
componentWillMount()
render()
componentDidMount() =====> 常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
代码片段:
<body>
<div id="test">div>
<div id="test1">div>
<script type="text/babel">
//创建组件
class Count extends React.Component {
//构造器
constructor(props) {
console.log('Count---constructor');
super(props)
//初始化状态
this.state = { count: 0 }
}
//加1按钮的回调
add = () => {
//获取原状态
const { count } = this.state
//更新状态
this.setState({ count: count + 1 })
}
//卸载组件按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//强制更新按钮的回调
force = () => {
this.forceUpdate()
}
//组件将要挂载的钩子
componentWillMount () {
console.log('Count---componentWillMount');
}
//组件挂载完毕的钩子
componentDidMount () {
console.log('Count---componentDidMount');
}
//组件将要卸载的钩子
componentWillUnmount () {
console.log('Count---componentWillUnmount');
}
//控制组件更新的“阀门”
shouldComponentUpdate () {
console.log('Count---shouldComponentUpdate');
return true
}
//组件将要更新的钩子
componentWillUpdate () {
console.log('Count---componentWillUpdate');
}
//组件更新完毕的钩子
componentDidUpdate () {
console.log('Count---componentDidUpdate');
}
render () {
console.log('Count---render');
const { count } = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
<hr />
</div>
)
}
}
//父组件A
class A extends React.Component {
//初始化状态
state = { carName: '奔驰' }
changeCar = () => {
this.setState({ carName: '奥拓' })
}
//组件将要挂载的钩子
componentWillMount () {
console.log('A---componentWillMount');
}
//组件挂载完毕的钩子
componentDidMount () {
console.log('A---componentDidMount');
}
//控制组件更新的“阀门”
shouldComponentUpdate () {
console.log('A---shouldComponentUpdate');
return true
}
//组件将要更新的钩子
componentWillUpdate () {
console.log('A---componentWillUpdate');
}
//组件更新完毕的钩子
componentDidUpdate () {
console.log('A---componentDidUpdate');
}
render () {
console.log('A---render');
return (
<div>
<div>我是A组件</div>
<button onClick={this.changeCar}>换车</button>
{ /*组件嵌套,调用子组件内容*/}
<B carName={this.state.carName} />
</div>
)
}
}
//子组件B
class B extends React.Component {
//组件将要挂载的钩子
componentWillMount () {
console.log('B---componentWillMount');
}
//组件挂载完毕的钩子
componentDidMount () {
console.log('B---componentDidMount');
}
//组件将要接收新的props的钩子
componentWillReceiveProps (props) {
console.log('B---componentWillReceiveProps', props);
}
//控制组件更新的“阀门”
shouldComponentUpdate () {
console.log('B---shouldComponentUpdate');
return true
}
//组件将要更新的钩子
componentWillUpdate () {
console.log('B---componentWillUpdate');
}
//组件更新完毕的钩子
componentDidUpdate () {
console.log('B---componentDidUpdate');
}
render () {
console.log('B---render');
return (
<div>我是B组件,接收到的车是:{this.props.carName}</div>
)
}
}
//渲染组件
ReactDOM.render(<Count />, document.getElementById('test'))
ReactDOM.render(<A />, document.getElementById('test1'))
script>
body>
html>
1. 初始化阶段:
由ReactDOM.render()触发---初次渲染
constructor()
在 React 组件挂载之前,会调用它的构造函数。主要用于初始化state、为实例方法绑定this。如果组件类继承自React.Component,在构造函数中应先调用super(props),需要注意的是,不用在构造函数中使用this.setState()。还可以更改事件处理程序this的指向。
static getDerivedStateFromProps(props, state)
响应 Props 变化之后进行更新的方式。这个生命周期的功能实际上就是将传入的props映射到state上面。 该方法是一个静态方法,无法通过this直接访问。这个函数会在每次re-rendering之前被调用。该方法的返回值会修改state,如果不想修改state,则直接返回null
render()
该方法是 class 组件中唯一必须实现的方法。render函数应该是一个纯函数,意味着在不修改state值的时候该函数的返回值是一样的。
componentDidMount() =====> 常用
会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在componentWillUnmount() 里取消订阅 。
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
根据该方法返回值,返回值默认为true判断 React 组件的输出是否受当前 state 或 props 更改的影响,返回值默认为true。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为
render()
getSnapshotBeforeUpdate(prevProps, prevState)
该钩子会在dom和refs渲染之前调用,返回的值可以传递给componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot)
会在更新后会被立即调用,首次渲染不会执行此方法。当组件更新后,可以在此处对DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。你也可以在componentDidUpdate() 中直接调用 setState() ,但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额 外的重新渲染,虽然用户不可⻅,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
代码片段:
<body>
<div id="test">div>
<script type="text/javascript" src="../js/17.0.1/react.development.js">script>
<script type="text/javascript" src="../js/17.0.1/react-dom.development.js">script>
<script type="text/javascript" src="../js/17.0.1/babel.min.js">script>
<script type="text/babel">
//创建组件
class Count extends React.Component {
//构造器
constructor(props) {
console.log('Count---constructor');
super(props)
//初始化状态
this.state = { count: 0 }
}
//加1按钮的回调
add = () => {
//获取原状态
const { count } = this.state
//更新状态
this.setState({ count: count + 1 })
}
//卸载组件按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//强制更新按钮的回调
force = () => {
this.forceUpdate()
}
//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
static getDerivedStateFromProps(props, state) {
console.log('getDerivedStateFromProps', props, state);
//return {...props}
return null
}
//在更新之前获取快照
getSnapshotBeforeUpdate() {
console.log('getSnapshotBeforeUpdate');
return 'atguigu'
}
//组件挂载完毕的钩子
componentDidMount() {
console.log('Count---componentDidMount');
}
//组件将要卸载的钩子
componentWillUnmount() {
console.log('Count---componentWillUnmount');
}
//控制组件更新的“阀门”
shouldComponentUpdate() {
console.log('Count---shouldComponentUpdate');
return true
}
//组件更新完毕的钩子
componentDidUpdate(preProps, preState, snapshotValue) {
console.log('Count---componentDidUpdate', preProps, preState, snapshotValue);
}
render() {
console.log('Count---render');
const { count } = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<Count count={199} />, document.getElementById('test'))
script>
body>
html>
现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。