React学习#01 组件的定义和 state 以及props的使用 官方文档
1. 特点
- 数据单项绑定,自上而下流动
- 支持组件封装和组件间的引用组合
- JSX/TSX语法的使用
- 使用虚拟DOM操作(diff更新【深度优先,同级比较】)
2. 组件定义
组件名称首字母必须大写,React以此来区别组件和普通的Html标签
2.1 通过class定义组件(React 16.8提供Hook,允许在函数组中使用state和其他React特性,官方建议以后使用函数声明组件,可只做参考理解)
class InputByClass extends React.Component<any, {value:string}>{
//构造函数
constructor(props:any) {
console.log('construct')
super(props);
this.state = {value:''};
this.onClick= this.onClick.bind(this);
}
//会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
// 返回一个对象来更新 state,如果返回 null 则不更新任何内容
static getDerivedStateFromProps(prevProps: Readonly<any>, prevState: Readonly<{ value: string }>){
console.log('state',prevState,'props',prevProps);
return null;
}
onClick:(e:string)=>void = (e)=>{
this.setState({value:e});
}
//组件触发更新渲染调用 入参原state 原props
//hook类似实现 useEffect(()=>{}) 集成 componentDidUpdate+componentDidMount
componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<{ value: string }>) {
console.log('component update');
}
//组件触发更新前会调用 入参 更新后的props,state 返回boolean类型 true:更新 false:阻止更新
//不常用 可用于于父组件重新时控制渲染子组件是否渲染
//注意 hook类似实现 const Component = React.memo((props) => {组件},((prevProps, nextProps)=>{return true})); 结果返回判断相反 局限:只能判断props的更改
shouldComponentUpdate(nextProps: Readonly<any>, nextState: Readonly<{ value: string }>): boolean {
return true;
}
//组件挂载后调用,组件卸载前只会调用一次
//hook类似实现 useEffect(()=>{},[])
componentDidMount() {
console.log('component did');
}
//卸载使用 用于清除处理
//hook类似 useEffect(()=>{return ()=>{清除函数}) useEffect一个清除函数函数 更新和卸载时react会自动调用
componentWillUnmount() {
console.log('component unmount');
}
//渲染
render() {
console.log('render')
return <input value={this.props.value} onChange={(e)=>{this.onClick(e.target.value)}}/>
}
}
2.2通过函数定义组件(以后的主流方式)
const InputByFC:React.FC<any> = (props)=>{
useEffect(()=>{
console.log('hook component did')
},[props])
const [state,setState] = useState<{value:string}>({value:''});
return( <input value={state.value} onChange={e=>{setState({value:e.target.value})}}/>)
}
3. state和props
3.1 state
state是React组件内部的状态,类似于Java类中的私有化变量,由于数据单向流向的特性,只能在自己组件的内部以及子组件中使用,当值发生变化会触发组件的重新渲染
tip:React关于state值的比较使用的是 ===,类似于Java,比较的是对象的地址而非内容,所以如果state类型为对象时,单纯改变某个属性值不会触发更新,需要重新复制一个新的对象
3.1.1 class中使用state
state可以使用两种方式赋值,构造函数使用this.state初始化赋值,其他函数中必须使用this.setState
/**
* 显示state值 -> 按钮点击修改组件state数据(value值加一)->触发更新页面上至下重新渲染 ->state值显示为1
*/
/
class ClassUseSate extends React.Component<any, {value:number}>{
private value:number = 0;
constructor(props:any) {
super(props);
this.state = {value:this.value}
}
render() {
return(<div>{this.state.value}<button onClick={()=>{this.setState({value:this.value++})}}>+</button></div>)
}
}
3.1.2 在函数组件中使用Hook变更state(不需要显示地定义state,由React来维护)
const FunctionUseState:React.FC<any> = (props)=>{
const [value,setValue] = useState<number>(0);
return(<div>{value}<button onClick={()=>{setValue(value+1)}}>+</button></div>);
}
3.1.3 比较
3.1.3.1 不同
- state的定义语法不同,在class中由于继承的是React的Component,名称是约定好的,赋值和初始化只能使用this.state或者this.setSate
但是在函数式组件中,可以使用useSate方法获取React对内部state管理的方法从而控制组件的更新 - class组件中state只会一个对象(更新时会合并,Hook不会,可以在使用Hook的方法中合并后再设置state达到类似效果),而在函数式组件中useState可以做拆分,分别对不同的情况定义不同的state使组件的控制更加细化
3.1.3.2 相同
- 本质是相同的,都是对React内部的state进行维护,只是定义方法不同
3.1.3.3 函数式组件+Hook的优势和不足
- 优势:使用函数定义代替class的定义,使用Hook解决了对组件内部函数和state的调用和维护(例如 uesSate实现了对state的管理,useEffect实现了类似于生命周期方法的调用等),通过使用函数定义,Hook管理使得函数
式组件相较于class定义的组件更加易懂,简便。 - 不足:官网提示目前暂时还没有对应不常用的 getSnapshotBeforeUpdate,getDerivedStateFromError 和 componentDidCatch 生命周期的 Hook 等价写法,但会计划尽早把它们加进来。
3.2 props
props为组件的入参,不管是函数式定义,还是class定义都应该是只读的,另外class定义必须调用父类super的方法
// props为组件参数
//class定义
class ClassProps extends React.Component<any, any>{
constructor(props:any) {
super(props);
this.state = {};
}
render() {
return (<></>);
}
}
//函数定义
const FunctionPros:React.FC = (props:any)=>{
return(<></>);
}
4. 总结
虽然class定义的组件会继续兼容,但是鉴于函数式组件+Hook已经能处理大部分场景,而且各大主流框架也开始采用这种方法,class写法可用于结合理解组件的生命周期,
维护旧项目只做了解即可,之后的使用还是建议使用函数组件+Hook方法