React 开发必须知道的 34 个技巧【近1W字】
前言
React 是前端三大框架之一,在开发中也是一项技能;
本文从实际开发中总结了 React 开发的一些技巧技巧,适合 React 初学或者有一定项目经验的同学
1 组件通讯
1.1 props
子组件
import React from "react";
import PropTypes from "prop-types";
import { Button } from "antd";
export default class EightteenChildOne extends React.Component {
static propTypes = { //propTypes校验传入类型,详情在技巧11
name: PropTypes.string
};
click = () => {
// 通过触发方法子传父
this.props.eightteenChildOneToFather("这是 props 改变父元素的值");
};
render() {
return (
<div>
<div>这是通过 props 传入的值{this.props.name}</div>
<Button type="primary" onClick={this.click}>
点击改变父元素值
</Button>
</div>
);
}
}
复制代码
父组件
<EightteenChildOne name={'props 传入的 name 值'} eightteenChildOneToFather={(mode)=>this.eightteenChildOneToFather(mode)}></EightteenChildOne>
// 或者
<EightteenChildOne name={'props 传入的 name 值'} eightteenChildOneToFather={this.eightteenChildOneToFather.bind(this)}></EightteenChildOne>
复制代码
props 传多个值时:
传统写法
const {dataOne,dataTwo,dataThree} = this.state
<Com dataOne={dataOne} dataTwo={dataTwo} dataThree={dataThree}>
复制代码
升级写法
<Com {...{dataOne,dataTwo,dataThree}}>
复制代码
1.2 props 升级版
原理:子组件里面利用 props 获取父组件方法直接调用,从而改变父组件的值
注意: 此方法和 props 大同小异,都是 props 的应用,所以在源码中没有举例
调用父组件方法改变该值
// 父组件
state = {
count: {}
}
changeParentState = obj => {
this.setState(obj);
}
// 子组件
onClick = () => {
this.props.changeParentState({ count: 2 });
}
复制代码
1.3 Provider,Consumer和Context
1.Context在 16.x 之前是定义一个全局的对象,类似 vue 的 eventBus,如果组件要使用到该值直接通过this.context获取
//根组件
class MessageList extends React.Component {
getChildContext() {
return {color: "purple",text: "item text"};
}
render() {
const {messages} = this.props || {}
const children = messages && messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: React.PropTypes.string
text: React.PropTypes.string
};
//中间组件
class Message extends React.Component {
render() {
return (
<div>
<MessageItem />
<Button>Delete</Button>
</div>
);
}
}
//孙组件(接收组件)
class MessageItem extends React.Component {
render() {
return (
<div>
{this.context.text}
</div>
);
}
}
MessageItem.contextTypes = {
text: React.PropTypes.string //React.PropTypes在 15.5 版本被废弃,看项目实际的 React 版本
};
class Button extends React.Component {
render() {
return (
<button style={
{background: this.context.color}}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: React.PropTypes.string
};
复制代码
2.16.x 之后的Context使用了Provider和Customer模式,在顶层的Provider中传入value,在子孙级的Consumer中获取该值,并且能够传递函数,用来修改context 声明一个全局的 context 定义,context.js
import React from 'react'
let { Consumer, Provider } = React.createContext();//创建 context 并暴露Consumer和Provider模式
export {
Consumer,
Provider
}
复制代码
父组件导入
// 导入 Provider
import {Provider} from "../../utils/context"
<Provider value={name}>
<div style={
{border:'1px solid red',width:'30%',margin:'50px auto',textAlign:'center'}}>
<p>父组件定义的值:{name}</p>
<EightteenChildTwo></EightteenChildTwo>
</div>
</Provider>
复制代码
子组件
// 导入Consumer
import { Consumer } from "../../utils/context"
function Son(props) {
return (
//Consumer容器,可以拿到上文传递下来的name属性,并可以展示对应的值
<Consumer>
{name => (
<div
style={
{
border: "1px solid blue",
width: "60%",
margin: "20px auto",
textAlign: "center"
}}
>
// 在 Consumer 中可以直接通过 name 获取父组件的值
<p>子组件。获取父组件的值:{name}</p>
</div>
)}
</Consumer>
);
}
export default Son;
复制代码
1.4 EventEmitter
EventEmiter 传送门 使用 events 插件定义一个全局的事件机制
1.5 路由传参
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.query
<Route path='/query' component={Query}/>
<Link to={
{ pathname : '/query' , query : { name : 'sunny' }}}>
this.props.history.push({pathname:"/query",query: { name : 'sunny' }});
读取参数用: this.props.location.query.name
复制代码
3.state
<Route path='/sort ' component={Sort}/>
<Link to={
{ pathname : '/sort ' , state : { name : 'sunny' }}}>
this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }});
读取参数用: this.props.location.query.state
复制代码
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
复制代码
这个在 react-router-dom: v4.2.2有 bug,传参跳转页面会空白,刷新才会加载出来
5.优缺点
1.params在HashRouter和BrowserRouter路由中刷新页面参数都不会丢失
2.state在BrowserRouter中刷新页面参数不会丢失,在HashRouter路由中刷新页面会丢失
3.query:在HashRouter和BrowserRouter路由中刷新页面参数都会丢失
4.query和 state 可以传对象
复制代码
1.6 onRef
原理:onRef 通讯原理就是通过 props 的事件机制将组件的 this(组件实例)当做参数传到父组件,父组件就可以操作子组件的 state 和方法
EightteenChildFour.jsx
export default class EightteenChildFour extends React.Component {
state={
name:'这是组件EightteenChildFour的name 值'
}
componentDidMount(){
this.props.onRef(this)
console.log(this) // ->将EightteenChildFour传递给父组件this.props.onRef()方法
}
click = () => {
this.setState({name:'这是组件click 方法改变EightteenChildFour改变的name 值'})
};
render() {
return (
<div>
<div>{this.state.name}</div>
<Button type="primary" onClick={this.click}>
点击改变组件EightteenChildFour的name 值
</Button>
</div>
);
}
}
复制代码
eighteen.jsx
<EightteenChildFour onRef={this.eightteenChildFourRef}></EightteenChildFour>
eightteenChildFourRef = (ref)=>{
console.log('eightteenChildFour的Ref值为')
// 获取的 ref 里面包括整个组件实例
console.log(ref)
// 调用子组件方法
ref.click()
}
复制代码
1.7 ref
原理:就是通过 React 的 ref 属性获取到整个子组件实例,再进行操作
EightteenChildFive.jsx
// 常用的组件定义方法
export default class EightteenChildFive extends React.Component {
state={
name:'这是组件EightteenChildFive的name 值'
}
click = () => {
this.setState({name:'这是组件click 方法改变EightteenChildFive改变的name 值'})
};
render() {
return (
<div>
<div>{this.state.name}</div>
<Button type="primary" onClick={this.click}>
点击改变组件EightteenChildFive的name 值
</Button>
</div>
);
}
}
复制代码
eighte