Open xiaochengzi6 opened 2 years ago
当使用this.state状态来取决value值的时候无论用户怎么输入都不会改变其控件[\ \\]的值
class Input extends React.Component{ constructor(props){ super(props); this.state={value:''}; } reder(){ return( <div> //这里就被控制了 <input value={this.state.value} /> </div> ) } }
React.js 认为所有的状态都应该由 React.js 的 state 控制,只要类似于 \ 、 \ 、 \ 这样的输入控件被设置了 value 值,那么它们的值永远以被设置的值为准。值不变, value 就不会变化。在 React.js 当中必须要用 setState 才能更新组件的内容,所以我们需要做的就是:监听输入框的 onChange 事件,然后获取到用户输入的内容,再通过 setState 的方式更新 state 中的 username 这样 input 的内容才会更新。
class Input extends React.Component{ constructor(props){ super(props); this.state={value:''}; } handchange(event){ this.setState( {value: event.target.value} ) } render(){ return( <div> <input value={this.state.value //1. onChange={this.handchange.bind(this)} } /> </div> ) } }
默认配置 defaultProps :用于默认配置props的各个属性。
props 不可变:你不能改变一个组件被渲染的时候传进来的props。但是你可以通过父组件主动重新渲染的方式来传入新的props,从而达到更新的效果。
state 的主要作用是用于组件保存、控制、修改自己的可变状态,state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState 方法进行更新,setState 会导致组件的重新渲染。 props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的props,否则组件的props永远保持不变。
state 的主要作用是用于组件保存、控制、修改自己的可变状态,state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState 方法进行更新,setState 会导致组件的重新渲染。
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的props,否则组件的props永远保持不变。
两者的差异:
state和props有着千丝万缕的关系。它们都可以决定组件的行为和显示形态。一个组件的 state 中的数据可以通过 props 传给子组件,一个组件可以使用外部传入的 props 来初始化自己的 state。但是它们的职责其实非常明晰分明:state 是让组件控制自己的状态,props 是让外部对组件自己进行配置。由此可以分出由状态组件和无状态组件。
constructor(props)
如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。反之:
class Toggle extends React.Component { constructor(props) { super(props); //1.初始化state this.state = {isToggleOn: true}; //2.为了方法绑定this this.handleClick = this.handleClick.bind(this);// 为了在回调中使用 `this`,这个绑定是必不可少的 } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('root') );
顺便在看看下面四种事件处理this的绑定的几种用法。
class Input extends React.Component { constructor(props) { ... } //3. handchange = (event) => { this.setState( {value: event.target.value} ) } render(){ return( <div> <input value={this.state.value onChange={this.handchange} } /> </div> ) } }
class Input extends React.Component { constructor(props) { ... } //4. handchange(event){ this.setState( {value: event.target.value} ) } render(){ return( <div> <input value={this.state.value onChange={()=>{this.handchange()}} } /> </div> ) } }
在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前前调用 super(props)。否则,this.props 在构造函数中可能会出现未定义的 bug。
super(props)
this.props
在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state:
constructor()
setState()
this.state
constructor(props) { super(props); // 不要在这里调用 this.setState() this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); }
要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 componentDidMount 中。 避免将 props 的值复制给 state
要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 componentDidMount 中。
componentDidMount
避免将 props 的值复制给 state
使用场景:当无法确定组件的全部内容的时候就可以使用这样预留的位置来间接的给其传递内容。
用法 :props.children
props.children
例如:
class Elediv extends React.Component{ reder(){ return( <div> {props.children}; </div> ) } } ReactDom.reder( <Elediv> <h1> Hello </h1> </Elediv>, document.getElementById('root') )
注意:
1.在 class 中必须调用 reder() 方法 2.return 返回的只能返回一个顶级元素。元素的概念描述了你想在屏幕上显示的内容 3.自定义组件的开头字母要大写,为了和 html 加以区分。 4.如果使用组件组合的方式的时候,最简单的方法是<Elediv/>r如果里面需要传入某些元素的时候可以使用<Elediv><h1>Hello</h1></Elediv>当然Elediv组件也要去接收它,不然就不会显示出来。接收的方法就是上个例子定义的
1.在 class 中必须调用 reder() 方法
2.return 返回的只能返回一个顶级元素。元素的概念描述了你想在屏幕上显示的内容
3.自定义组件的开头字母要大写,为了和 html 加以区分。
4.如果使用组件组合的方式的时候,最简单的方法是<Elediv/>r如果里面需要传入某些元素的时候可以使用<Elediv><h1>Hello</h1></Elediv>当然Elediv组件也要去接收它,不然就不会显示出来。接收的方法就是上个例子定义的
<Elediv/>
<Elediv><h1>Hello</h1></Elediv>
规定:这里规定引用其他组件的组件称为父组件,被应用的组件是子组件。
解释:现在就可以通过在父组件中可以往子组件中传入某些元素,子组件通过props对象中children来获取。这里就相当于它是自动的把这个值给保存到children中,然后调用这个属性就可以获得被传入的元素。这里先认为它(children)为props的属性。
另一种方式:
class Elespan extends React.Component{ reder(){ return( <h1>Heloow</h1> ) } } class Elediv extends React.Component{ reder(){ return( <div> {props.left} </div> ) } } ReactDom.reder( <Elediv left= {<Elespan />} />, document.getElementById('root') )
可以不使用children的方法,这种更加灵活,在组合的过程中也比较比较精细
ReactDOM.reder()这个方法通常构建与一个根 dom 节点其内容都在这个根 dom 节点中完成 参数1:构成的组件;参数2:要渲染的 dom 节点; 首次调用会替换里面所有的dom节点,后续调用会使用diff算法,某个节点变化才会更新某个节点,
ReactDOM.reder()这个方法通常构建与一个根 dom 节点其内容都在这个根 dom 节点中完成
ReactDOM.reder()
参数1:构成的组件;参数2:要渲染的 dom 节点;
首次调用会替换里面所有的dom节点,后续调用会使用diff算法,某个节点变化才会更新某个节点,
style的设置
在 React.js 中你需要把 CSS 属性变成一个对象再传给元素:
<h1 style={{fontSize:'12px', color:'red'}}>React</h1>
由于参数的问题React.js就提供了一种机制,让你可以给组件的配置参数加上类型验证,就用上述的评论组件例子,你可以配置 Comment只能接受对象类型的comment参数,你传个数字进来组件就强制报错。
React.js
Comment
comment
hook就是钩子的意思,它可以让你在函数组件中钩入react的特性,目的就是加强函数组件,不使用类就可以写出全功能的组件,函数组件尽量满足纯函数,如果需要副作用就需要相应的钩子钩入到函数中
1.hook不能在class组件中写入 2.只能在函数最外层调用,不能再循环,条件判断或者子函数中使用 3.只能在react函数组件中使用,Hook 在 class 内部是不起作用的
1.hook不能在class组件中写入
2.只能在函数最外层调用,不能再循环,条件判断或者子函数中使用
3.只能在react函数组件中使用,Hook 在 class 内部是不起作用的
使用useState{状态钩子},它允许你在react函数组件中添加state:
useState
const [count,SetCount] = useState(0);
这里定义了一个count变量把它设置为0 react会记住它当前渲染的值,并提供给最新值给我们的函数。count来接受useState中的“state变量”就和class中的this.State=({count:0})类似;
0
react会记住它当前渲染的值,并提供给最新值给我们的函数。
this.State=({count:0})
你可以给useState参数传入数字或者是字符串它只有一个参数,useState的返回值是两个值的数组,第一个值是当前的state,第二个值是更新state的函数。这里可以明显的感觉到第一个值是一个变量里面保存着内部的state,指向状态的当前值 还可以不断的更新它 第二个值是返回一个函数用来更新状态约定是前缀加以set
useState参数
变量
函数
set
你如果想更新的话可以这样使用setCount(count+1)所以setCount在class中类似于this.setState({count:1})
setCount(count+1)
this.setState({count:1})
useEffect副作用钩子
useEffect
作用:这个钩子可以让你在函数组件中执行一些副作用的操作,函数组件最好写成是纯函数这样避免一些难以发现的问题,如果要在函数组件中写一些具有副作用的东西,那么useEffect可以胜任。
如果熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
componentDidUpdate
componentWillUnmount
这三者分别在生命周期的三个阶段,挂载阶段: componentDidMount;更新阶段:componentDidUpdate; 卸载阶段:componentWillUnmount这就说明这个副作用可以一直持续着直到组件被卸载。
那么也就可以这样理解,你在useEffect函数写入的东西相当于你分别在那三个函数内写进去的一样。useEffect函数是那三者的组合版调用起来也更加的方便。
useEffect函数
这个钩子会在每次渲染之后都会执行,(第一次渲染/之后的更新)React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。因为副作用有的是直接操作dom元素的。也就是说 DOM 创建完成才会运行 Effect 钩子函数。
在官方文档中它有两种常见的副作用操作:
1.需要清除 2.不需要清除
1.需要清除
2.不需要清除
清除的概念和生命周期里面componentWillUnmount()函数的作用类似,这个函数是在组件销毁或者卸载之前调用目的是清除必要的清理操作。
componentWillUnmount()
1.不需要清除的
只想在 React 更新 DOM 之后运行一些额外的代码。比如发送网络请求,手动变更 DOM,记录日志,这些都是常见的无需清除的操作。因为我们在执行完这些操作之后,就可以忽略他们了。让我们对比一下使用 class 和 Hook 都是怎么实现这些副作用的。
2.需要清除的
例如订阅外部数据源。这种情况下,清除工作是非常重要的,可以防止引起内存泄露!
如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它
const func = () => { const [state, setState] = useState(null) useEffect(() => { //副作用 }) return ()=>{ //清除之前副作用的操作 } }
并且useEffect 默认处理更新的问题。它会在调用一个新的 effect 之前对前一个 effect 进行清理
useEffect 用法:
useEffect()用来引入副作用操作,它接收两个参数:第一个参数是一个函数,第二个参数是一个数组用于给useEffect依赖,只要数组中的东西发生变化就会执行useEffect函数。第二个参数可以省略。忽略第二个参数时首次渲染和每次组件渲染都会执行useEffect()
useEffect()
const [ count, setCount ] = useState(0) useEffect(()=>{ document.title = 'Hello' }) //或者 const [ count, setCount ] = useState(0) useEffect(()=>{ document.title = "HELLo ${count}" },[count]) //如果 count === useEffect 中的 count 的话那么就不会执行 useEffect 函数 实现性能优化 //这样做的好处是可以避免每次渲染都执行清理或者执行 effect 导致性能的问题。
第二个参数还可以是一个空的数组。但是这个useEffect()只会执行一次{在组件加载入DOM中也就是第一次渲染,{首次渲染}
自定义 Hook
1.函数命名必须以 use 开始 2.可以在自定义 Hook 中重复使用其他的 hook
1.函数命名必须以 use 开始
2.可以在自定义 Hook 中重复使用其他的 hook
const App = () => { const [ addnums, setAddnums ] = useState(0) return ( <div> <p>Number: {addnums}</p> <button onClick={ () => setAddnums(addnums+1)} >点击</button> </div> ) } // ---------------------------------------------------------------- //自定义组件 useNumber const useNumber = () => { const [addnums, setAddnums] = useState(0) const addNumber = () => { setAddnums(addnums + 1) } return { addnums,addNumber } } const App = () => { //开始使用 const {addnums:num,addNumber:handleAddnumber} = useNumber() return( <div> <p> Number: {num}</p> <button onClick={handleAddnumber}>Click</button> </div> ) }
挂载 ----->更新----->卸载
挂载:组件的实例被创建并插入到DOM中
更新:组件的props或state发生变化时触发更新
卸载:组件从dom中移除
这三者是组件的生命过程,每个阶段会调用相应的函数来处理
1.组件挂载到DOM上:
constructor() static getDerivedStateFromProps() render() componentDidMount()
static getDerivedStateFromProps()
render()
componentDidMount()
2.组件更新的时候
3.组件卸载的时候
下面是几个适合使用 refs 的情况:
Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。refs最重要的就是获取 dom 节点来进行操作
React.createRef()
ref
//----1 class MyComponent extends Component { constructor(props) { super(props); this.myRef = React.createRef(); } render() { return <div ref={this.myRef} />; } } //----2 //必须通过 forwardRef 才能接收 ref 参数 const FancyButton = React.forwardRef((props, ref) => { return <button ref={ref} /> }) const ref = React.createRef() <FancyButton ref={ref} /> //----错误的 const Func = (ref,props) => { return ( <div ref={ref}></div> ) }
当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问
render
current
当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。 你不能在普通函数组件上使用 ref 属性,因为他们接收不到。-常规函数不能接收-
如果要在函数组件内部中使用ref那么你必须采用钩子或者是forwardRef来配合使用。在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件
function CustomTextInput(props) { // 这里必须声明 textInput,这样 ref 才可以引用它 const textInput = useRef(null); function handleClick() { textInput.current.focus(); } return ( <div> <input type="text" ref={textInput} /> <input type="button" value="Focus the text input" onClick={handleClick} /> </div> ); }
回调函数Refs
不同于传递 createRef() 创建的 ref 属性,你会传递一个函数。这个函数中接受 React 组件实例或 HTML DOM 元素作为参数,以使它们(this.textInput)能在其他地方被存储和访问。
createRef()
class CustomTextInput extends Component { constructor(props) { super(props); this.textInput = null; //ref 函数 this.setTextInputRef = element => { this.textInput = element; }; this.focusTextInput = () => { if (this.textInput) this.textInput.focus(); }; } render() { return ( <div> <input type="text" ref={this.setTextInputRef} /> <input type="button" value="Focus the text input" onClick={this.focusTextInput} /> </div> ); } }
你可以在组件间传递回调形式的 refs
function CustomTextInput(props) { return ( <div> <input ref={props.inputRef} /> </div> ); } class Parent extends React.Component { render() { return ( <CustomTextInput inputRef={el => this.inputElement = el} /> ); } }
这里在 Parent 中的 this.inputElement 会被设置为与 CustomTextInput 中的 input 元素相对应的 DOM 节点。
Parent
this.inputElement
CustomTextInput
input
this.textInput = null; this.setTextInputRef = element => { this.textInput = element; // ref 传递函数的 接收 element 保存在 textInput
在高阶组件中转发 Ref 但要注意的是 对高阶组件添加 ref 则 ref 就会应用最外层的容器组件而不是包裹组件
const logProps = (Hfunc) => { // 容器组件 class LogProps extends React.Component { render() { return ( // 包裹组件 <Hfunc /> ) } } } class FancButton extends React.Compoment { .... } Fancbutton = logProps(FancButton); const ref = React.creatRef(); <Fancbutton ref={ref} />; // ref 并不会指向 Hfunc(FancBtton组件)他会指定为容器组件 LogProps
可以采取这样的操作
const logProps = (Hfunc) => { // 容器组件 class LogProps extends React.Component { render() { const {forwardRef,...rest} = this.props return ( // 包裹组件 <Hfunc ref={forwardRef} {...rest}/> ) } } return React.forwardRef((props, ref) => { return <LogProps forwardRef={ref} {...rest} /> }) } class FancButton extends React.Compoment { .... } Fancbutton = logProps(FancButton); const ref = React.creatRef(); <Fancbutton ref={ref} />;
高阶组件就是一个函数给他传入一个组件他将返回一个新的组件 。传入的组件会变成在函数内定义的组件的子组件。
import React {Component} from 'react' const Button = (Wreep) => { class NewCompoent extends Component { ... //自定义逻辑 render(){ return ( <Wreep > ) } } return NewComponent }
高阶组件它的目的就是封装了一个组件的功能 ,你只需要将要接收这个功能的组件当成函数的参数传入进高阶组件中 它返回的组件就是你所要的(接收这个功能后的组件)
import React {Component} from 'react' const Wrate = (WrappendComponent) => { //原本定义的组件 class NewComponent extends Component { //内部逻辑 constructor(){ super() this.state = {data: null} } //获得缓存的name然后存入到 state.data中 componentWillMount(){ let data = locaStorage.getItem(name) this.setState({data}) } //将state.data传入到下一个组件中 render(){ return <WrappendComponent data={this.state.data}/> } } } class InputWithUserName extends Component { constructor(props){ super(props); } render(){ //开始接收这个数据(state.data) return <input value={this.props.data} /> } } //高级组件返回的新组件被InputWithUserName命名 InputWithUserName = wrate(InputWithUserName, 'username')
无一例外:如果看到高级组件就把他当作是一个函数接收一个组件返回一个新组件,在看其内部就是制定了一些逻辑 运行完后的东西在传入到接收组件中 最后在返回这个组件。如果想使用这个逻辑那么传入的参数(组件)必须要对应上比如InputWithUserName它就必须要有{this.props.data}来接收才行。
编写规范
组件的私有方法都用_开头,所有事件监听的方法都用handle开头。把事件监听方法传给组件的时候,属性名用on开头。例如:
_
handle
on
<CommentInput onSubmit={this.handleSubmitComment.bind(this)} />
这样统一规范处理事件命名会给我们带来语义化组件的好处,监听(on)CommentInput的Submit事件,并且交给this去处理(handle )。这种规范在多人协作的时候也会非常方便。
组件的内容编写顺序如下:
1.static开头的类属性,如defaultProps、propTypes。构造函数,constructor` 。 2.getter/setter(还不了解的同学可以暂时忽略)。组件生命周期。 3._开头的私有方法。事件监听方法,handle* 。 4.render开头的方法,有时候render()方法里面的内容会分开到不同函数里面进行,这些函数都以render开头。render()方法。 如果所有的组件都按这种顺序来编写,那么维护起来就会方便很多,多人协作的时候别人理解代码也会一目了然。
1.static开头的类属性,如defaultProps、propTypes。构造函数,constructor` 。
static
defaultProps、propTypes
构造函数,
2.getter/setter(还不了解的同学可以暂时忽略)。组件生命周期。
3._开头的私有方法。事件监听方法,handle* 。
handle*
4.render开头的方法,有时候render()方法里面的内容会分开到不同函数里面进行,这些函数都以render开头。render()方法。 如果所有的组件都按这种顺序来编写,那么维护起来就会方便很多,多人协作的时候别人理解代码也会一目了然。
注意:你可以在类组件中用写constructor哪怕在render中使用了props但是你一旦写了这个构造函数那么你就要加上以下这些
constructor
class Index extends Conponent{ // --------V constructor(props){ // ---------V super(props) } render(){ return(...) } }
return中也不必返回React元素,你可以返回null这样它在页面中就隐藏起来了。
return
components/目录下放入无状态组件 containers/目录下放入有状态组件
阮一峰-轻松学会 React 钩子:以 useEffect() 为例
react官方文档
阮一峰-React Hooks 入门教程
受控组件
当使用this.state状态来取决value值的时候无论用户怎么输入都不会改变其控件[\ \\]的值
React.js 认为所有的状态都应该由 React.js 的 state 控制,只要类似于 \ 、 \ 、 \ 这样的输入控件被设置了 value 值,那么它们的值永远以被设置的值为准。值不变, value 就不会变化。在 React.js 当中必须要用 setState 才能更新组件的内容,所以我们需要做的就是:监听输入框的 onChange 事件,然后获取到用户输入的内容,再通过 setState 的方式更新 state 中的 username 这样 input 的内容才会更新。
state 和props的特点
默认配置 defaultProps :用于默认配置props的各个属性。
props 不可变:你不能改变一个组件被渲染的时候传进来的props。但是你可以通过父组件主动重新渲染的方式来传入新的props,从而达到更新的效果。
两者的差异:
state和props有着千丝万缕的关系。它们都可以决定组件的行为和显示形态。一个组件的 state 中的数据可以通过 props 传给子组件,一个组件可以使用外部传入的 props 来初始化自己的 state。但是它们的职责其实非常明晰分明:state 是让组件控制自己的状态,props 是让外部对组件自己进行配置。由此可以分出由状态组件和无状态组件。
构造函数 constructor()
如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。反之:
顺便在看看下面四种事件处理this的绑定的几种用法。
在
constructor()
函数中不要调用setState()
方法。如果你的组件需要使用内部 state,请直接在构造函数中为this.state
赋值初始 state:组合
使用场景:当无法确定组件的全部内容的时候就可以使用这样预留的位置来间接的给其传递内容。
用法 :
props.children
例如:
注意:
规定:这里规定引用其他组件的组件称为父组件,被应用的组件是子组件。
解释:现在就可以通过在父组件中可以往子组件中传入某些元素,子组件通过props对象中children来获取。这里就相当于它是自动的把这个值给保存到children中,然后调用这个属性就可以获得被传入的元素。这里先认为它(children)为props的属性。
另一种方式:
可以不使用children的方法,这种更加灵活,在组合的过程中也比较比较精细
注意:
style的设置
在 React.js 中你需要把 CSS 属性变成一个对象再传给元素:
由于参数的问题
React.js
就提供了一种机制,让你可以给组件的配置参数加上类型验证,就用上述的评论组件例子,你可以配置Comment
只能接受对象类型的comment
参数,你传个数字进来组件就强制报错。react hook
hook就是钩子的意思,它可以让你在函数组件中钩入react的特性,目的就是加强函数组件,不使用类就可以写出全功能的组件,函数组件尽量满足纯函数,如果需要副作用就需要相应的钩子钩入到函数中
注意:
使用
useState
{状态钩子},它允许你在react函数组件中添加state:这里定义了一个count变量把它设置为
0
react会记住它当前渲染的值,并提供给最新值给我们的函数。
count来接受useState中的“state变量”就和class中的this.State=({count:0})
类似;你可以给
useState参数
传入数字或者是字符串它只有一个参数,useState的返回值是两个值的数组,第一个值是当前的state,第二个值是更新state的函数。这里可以明显的感觉到第一个值是一个变量
里面保存着内部的state,指向状态的当前值 还可以不断的更新它 第二个值是返回一个函数
用来更新状态约定是前缀加以set
你如果想更新的话可以这样使用
setCount(count+1)
所以setCount在class中类似于this.setState({count:1})
useEffect
副作用钩子作用:这个钩子可以让你在函数组件中执行一些副作用的操作,函数组件最好写成是纯函数这样避免一些难以发现的问题,如果要在函数组件中写一些具有副作用的东西,那么
useEffect
可以胜任。如果熟悉 React class 的生命周期函数,你可以把
useEffect
Hook 看做componentDidMount
,componentDidUpdate
和componentWillUnmount
这三个函数的组合。这三者分别在生命周期的三个阶段,挂载阶段:
componentDidMount
;更新阶段:componentDidUpdate
; 卸载阶段:componentWillUnmount
这就说明这个副作用可以一直持续着直到组件被卸载。那么也就可以这样理解,你在
useEffect函数
写入的东西相当于你分别在那三个函数内写进去的一样。useEffect函数
是那三者的组合版调用起来也更加的方便。这个钩子会在每次渲染之后都会执行,(第一次渲染/之后的更新)React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。因为副作用有的是直接操作dom元素的。也就是说 DOM 创建完成才会运行 Effect 钩子函数。
在官方文档中它有两种常见的副作用操作:
清除的概念和生命周期里面
componentWillUnmount()
函数的作用类似,这个函数是在组件销毁或者卸载之前调用目的是清除必要的清理操作。1.不需要清除的
2.需要清除的
如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它
useEffect 用法:
useEffect()
用来引入副作用操作,它接收两个参数:第一个参数是一个函数,第二个参数是一个数组用于给useEffect
依赖,只要数组中的东西发生变化就会执行useEffect
函数。第二个参数可以省略。忽略第二个参数时首次渲染和每次组件渲染都会执行useEffect()
第二个参数还可以是一个空的数组。但是这个
useEffect()
只会执行一次{在组件加载入DOM中也就是第一次渲染,{首次渲染}自定义 Hook
生命周期
挂载 ----->更新----->卸载
挂载:组件的实例被创建并插入到DOM中
更新:组件的props或state发生变化时触发更新
卸载:组件从dom中移除
这三者是组件的生命过程,每个阶段会调用相应的函数来处理
1.组件挂载到DOM上:
2.组件更新的时候
3.组件卸载的时候
Refs
下面是几个适合使用 refs 的情况:
Refs 是使用
React.createRef()
创建的,并通过ref
属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。refs最重要的就是获取 dom 节点来进行操作当 ref 被传递给
render
中的元素时,对该节点的引用可以在 ref 的current
属性中被访问如果要在函数组件内部中使用ref那么你必须采用钩子或者是forwardRef来配合使用。在函数组件内部使用
ref
属性,只要它指向一个 DOM 元素或 class 组件回调函数Refs
不同于传递
createRef()
创建的ref
属性,你会传递一个函数。这个函数中接受 React 组件实例或 HTML DOM 元素作为参数,以使它们(this.textInput)能在其他地方被存储和访问。你可以在组件间传递回调形式的 refs
这里在
Parent
中的this.inputElement
会被设置为与CustomTextInput
中的input
元素相对应的 DOM 节点。在高阶组件中转发 Ref 但要注意的是 对高阶组件添加 ref 则 ref 就会应用最外层的容器组件而不是包裹组件
可以采取这样的操作
高阶组件
高阶组件就是一个函数给他传入一个组件他将返回一个新的组件 。传入的组件会变成在函数内定义的组件的子组件。
高阶组件它的目的就是封装了一个组件的功能 ,你只需要将要接收这个功能的组件当成函数的参数传入进高阶组件中 它返回的组件就是你所要的(接收这个功能后的组件)
例如:
无一例外:如果看到高级组件就把他当作是一个函数接收一个组件返回一个新组件,在看其内部就是制定了一些逻辑 运行完后的东西在传入到接收组件中 最后在返回这个组件。如果想使用这个逻辑那么传入的参数(组件)必须要对应上比如InputWithUserName它就必须要有{this.props.data}来接收才行。
context
编写规范
组件的私有方法都用
_
开头,所有事件监听的方法都用handle
开头。把事件监听方法传给组件的时候,属性名用on
开头。例如:这样统一规范处理事件命名会给我们带来语义化组件的好处,监听(on)CommentInput的Submit事件,并且交给this去处理(handle )。这种规范在多人协作的时候也会非常方便。
组件的内容编写顺序如下:
注意:你可以在类组件中用写
constructor
哪怕在render中使用了props但是你一旦写了这个构造函数那么你就要加上以下这些return
中也不必返回React元素,你可以返回null这样它在页面中就隐藏起来了。components/目录下放入无状态组件 containers/目录下放入有状态组件
参考文章
阮一峰-轻松学会 React 钩子:以 useEffect() 为例
react官方文档
阮一峰-React Hooks 入门教程