状态提示
在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
虽然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。由于“存在”于组件中的任何 state,仅有组件自己能够修改它,因此 bug 的排查范围被大大缩减了。此外,你也可以使用自定义逻辑来拒绝或转换用户的输入
总结一下:当某个状态被多个组件依赖或者影响的时候,就把该状态提升到这些组件的最近公共父组件中去管理,用 props 传递数据或者函数来管理这种依赖或着影响的行为。
组合 vs 继承
React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用
有些组件无法提前知晓它们子组件的具体内容。在 Sidebar(侧边栏)和 Dialog(对话框)等展现通用容器(box)的组件中特别容易遇到这种情况。
我们建议这些组件使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中
//父组件
function FancyBorder(props) {
return (
<div className={'box-color' + props.color}>
{props.children}
</div>
);
}
2
3
4
5
6
7
8
//子组件
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
我是子组件
</h1>
<p className="Dialog-message">
通过组合的方式嵌入到父组件中,父组件可以通过this.props.children来找到
</p>
</FancyBorder>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们
PropTypes
利用 ES7 的静态属性关键字 static
class PropTypeTwo extends React.Component {
static propTypes = {
name:PropTypes.string
};
render() {
return (
<div>
<div>{this.props.name}</div>
</div>
);
}
}
2
3
4
5
6
7
8
9
10
11
12
state 值改变的五种方式
方式 1
let {count} = this.state
this.setState({count:2})
2
方式 2 :callBack
this.setState(({count})=>({count:count+2}))
方式 3 :接收 state 和 props 参数
this.setState((state, props) => {
return { count: state.count + props.step };
});
2
3
方式 4:hooks
const [count, setCount] = useState(0)
// 设置值
setCount(count+2)
2
3
方式 5:state 值改变后调用
this.setState(
{count:3},()=>{
//得到结果做某种事
}
)
2
3
4
5
监听states 变化
1.16.x 之前使用componentWillReveiveProps
componentWillReceiveProps (nextProps){
if(this.props.visible !== nextProps.visible){
//props 值改变做的事
}
}
2
3
4
5
注意:有些时候componentWillReceiveProps在 props 值未变化也会触发,因为在生命周期的第一次render后不会被调用,但是会在之后的每次render中被调用 = 当父组件再次传送props
2.16.x 之后使用getDerivedStateFromProps,16.x 以后componentWillReveiveProps也未移除
export default class Six extends React.Component {
state = {
countOne:1,
changeFlag:''
};
clickOne(){
let {countOne} = this.state
this.setState({countOne:countOne+1})
};
static getDerivedStateFromProps (nextProps){
console.log('变化执行')
return{
changeFlag:'state 值变化执行'
}
}
render() {
const {countOne,changeFlag} = this.state
return (
<div>
<div>
<Button type="primary" onClick={this.clickOne.bind(this)}>点击加 1</Button><span>countOne 值为{countOne}</span>
<div>{changeFlag}</div>
</div>
</div>
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
高阶组件
如果一个函数 接受一个或多个函数作为参数或者返回一个函数 就可称之为 高阶函数。
下面就是一个简单的高阶函数:
function withGreeting(greeting = () => {}) {
return greeting;
}
2
3
高阶组件 的定义和 高阶函数 非常相似:
如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
下面就是一个简单的高阶组件:
function HigherOrderComponent(WrappedComponent) {
return <WrappedComponent />;
}
2
3
所以你可能会发现,当高阶组件中返回的组件是 无状态组件(Stateless Component) 时,该高阶组件其实就是一个 高阶函数,因为 无状态组件 本身就是一个纯函数。
无状态组件也称函数式组件。
React 中的高阶组件
就是类似高阶函数的定义,将组件作为参数或者返回一个组件的组件
1.属性代理
import React,{Component} from 'react';
const Seventeen = WrappedComponent =>
class extends React.Component {
render() {
const props = {
...this.props,
name: "这是高阶组件"
};
return <WrappedComponent {...props} />;
}
};
class WrappedComponent extends React.Component {
state={
baseName:'这是基础组件'
}
render() {
const {baseName} = this.state
const {name} = this.props
return <div>
<div>基础组件值为{baseName}</div>
<div>通过高阶组件属性代理的得到的值为{name}</div>
</div>
}
}
export default Seventeen(WrappedComponent)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.反向继承
const Seventeen = (WrappedComponent)=>{
return class extends WrappedComponent {
componentDidMount() {
this.setState({baseName:'这是通过反向继承修改后的基础组件名称'})
}
render(){
return super.render();
}
}
}
class WrappedComponent extends React.Component {
state={
baseName:'这是基础组件'
}
render() {
const {baseName} = this.state
return <div>
<div>基础组件值为{baseName}</div>
</div>
}
}
export default Seventeen(WrappedComponent);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
路由传参
1.params
<Route path='/path/:name' component={Path}/>
<link to="/path/2">xxx</Link>
this.props.history.push({pathname:"/path/" + name});
读取参数用:this.props.match.params.name
2
3
4
2.query
<Route path='/query' component={Query}/>
<Link to={{ path : '/query' , query : { name : 'sunny' }}}>
this.props.history.push({pathname:"/query",query: { name : 'sunny' }});
读取参数用: this.props.location.query.name
2
3
4
3.state
<Route path='/sort ' component={Sort}/>
<Link to={{ path : '/sort ' , state : { name : 'sunny' }}}>
this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }});
读取参数用: this.props.location.query.state
2
3
4
4.search
<Route path='/web/search ' component={Search}/>
<link to="web/search?id=12121212">xxx</Link>
this.props.history.push({pathname:`/web/search?id ${row.id}`});
读取参数用: this.props.location.search
2
3
4
5.优缺点
1.params和 search 只能传字符串,刷新页面参数不会丢
2.query和 state 可以传对象,但是刷新页面参数会丢失
2