React 介绍
React.createClass API React创建组件的时候,把所有功能参数都传给createClass来
var Demo = React.createClass({
getInitialState(){
return {
loading: false,
data: []
}
},
componentDidMount(){
console.log('componentDidMount')
},
componentDidUpdate(){
console.log('componentDidUpdate')
},
update(){
this.setState({
loading: true,
data: [
{
id:1,
name: '我是第一个'
}
]
})
},
render(){
return (
<div>
{
this.state.data.map(item=>{
return (
<span key={`key-${item.id}`}>{name}</span>
)
})
}
</div>
)
}
})
在es6出class后用了,React.Component
class Demo extends React.Component {
constructor(props){
super(props);
...
}
}
使用Class组件的时候,可以用constructor内部组件状态初始化为实例(this)的state属性。但是如果扩展子类,则必须使用super然后才能使用this。
还有就是React.Component 是在constructor里绑定事件的this,否则可能会有无法想像的this,找不到setState 之类的问题,当然类字段可以使用箭头函数了
class Demo extends React.Component {
constructor(props){
super(props);
this.update = this.update.bind(this)
}
update(){
this.setState({
loading: true,
})
},
update2:()=>{
}
}
共享非视觉逻辑
假设我们需要多个同一状态的组件,Demo的状态组件。现在,该状态及其处理逻辑位于Demo组件内部。我们将如何处理呢?最简单的方法就是复制所有用于获取和处理存储data的逻辑,然后将其粘贴到新组件中。简单,但不,还有一种更聪明的方法是创建一个高阶组件(HOC),该组件封装了所有共享逻辑,并将loading,data等数据作为参数传递给所需的任何组件。
function withDemo(Component){
return class WithDemo extends React.Component {
state={
loadgin: false,
data: []
}
}
componentDidMount(){
this.update(this.props.id)
}
componentDidUpdate(preProps){
if(preProps.id !== this.props.id){
this.update(this.props.id)
}
}
update:(id)=>{
this.setState({
loading: false,
data: Array.form(Array(4)).map(item=> Math.random().toString(36).slice(2) )
})
}
}
但是,如果有很多个HOC呢,最终呈现的结果比开始的更糟糕。HOC(和类似的模式)迫使您重组和包装组件。最终可能导致“包装器地狱”,这又使跟踪变得更加困难。
export defaut withHover(
withTheme(
withAuth(
withDemo(Demo)
)
)
)
面临的问题
- 我们将类用于React组件,这是当时最有意义的原因。
- 调用super(props)很烦人。
- this很难当位
- 通过生命周期方法组织组件会迫使我们在整个组件趾散布相关的逻辑。
- React没有共享非可视逻辑的良好原语。
Hooks
从 Reactv0.14.0开始,我们有两种创建组件的方法-类或函数。区别在于,如果我们的组件具有状态或需要使用生命周期方法,则必须使用一个类。否则,如果它只是接受参数并渲染了一些UI,则可以使用一个函数。
我们需要找到一种方法来增加功能组件具有状态和生命周期的能力,但是假设我们这样做了。我们将看到什么好处?
好了,我们不再需要调用super(props)。我们不再需要担心bind我们的方法或者this的关键字,并具我们不再需要使用class Fields。本质上。我们之前讨论的所有表面问题都将消失。
useState
useState接受一个参数,即状态的初始值。它返回的是一个数据。第一项是状态。第二项是更新状态的函数。
const loadingState = React.useState(true);
const loading = loadingState[0];
const setLoading = loadingState[1];
// 用es6数组解构可以写成
const [loading, setLoading] = React.useState(false);
console.log(loading) // false;
setLoading(true);
console.log(loading) // true
useEffect
无论是设置组件的初始状态,获取数据,更新DOM,还是其他任何事情-最终目标始终是同步。通常,将React Land之外的内容(API请求,DOM等)与React Land内的某些内容(组件状态)同步,反之亦然。
当我们考虑同步而不是生命周期事件时,它使我们可以将相关的逻辑部分组合在一起。为此,React给了我们另一个名为useEffect Hook
useEffect使您可以在功能组件中执行副作用。它带有两个参数,一个是函数和一个可选数组。该函数定义要运行的副作用,(可选)数组定义何时“重新同步”(或重新运行)效果。
// 当usename变化时页面标题更新
React.useEffect(()=>{
document,title = `你好,${usename}`
},[usename])
有了我们就可以把非视觉逻辑提取写成自定义Hooks,
自定义hooks开头约定是useXXX来命名。
const useUpdate = (id)=>{
const [loading, setLoading] = React.useState(false);
const [data, setData] = React.useState([]);
React.useEffect(()=>{
setLoading(true);
setData([]);
},[id])
return [loading, data];
}
const Demo = (id)=>{
const [loading, data] = useUpdate(id);
}
总结
hooks是为了更好的解决共享非视觉逻辑的,降低“包装器地狱”,还有子组件super(props)