react的组件是解决html标签构建应用的不足,它的好处是能把公共的功能单独抽离成一个文件作为一个组件,哪里需要就在哪里引入。
父子组件:组件的相互调用中,把调用者称为父组件,被调用者称为子组件。
一、父组件向子组件传值
在父组件引入子组件:
import ChildComponent from './ChildComponent';
1、传递值
父组件向子组件传值,在子组件标签里设置一个属性传递,例如data:<ChildComponent data={this.state.data}/>。
在子组件中通过this.props.data来获取,如附1代码。
2、传递方法
父组件向子组件传方法,在子组件标签设置一个属性传递,例如run:<ChildComponent run={this.run}/>。
在子组件里通过this.props来调用run方法,如附1代码。
3、传递整个组件
将整个父组件传给子组件,在子组件标签设置一个属性传递,例如parentCpt:<ChildComponent parentCpt={this}/>。
在子组件的方法里通过this.props.parentCpt来调用getParent,也可以调用state里的值,使用this.props.parentCpt.state,如附1代码。
传递其他的组件:
const Bar = <p>我是Bar组件</p>; //或
const Bar =()=> (<p>我是Bar组件</p>);
<ChildComponent component={Bar} /> //或
<ChildComponent component={<Bar/>} />
在子组件中:
{this.props.component}获取
const Bar =()=> (<p>我是Bar组件</p>);
<ChildComponent component={()=><Bar/>} />
传递的component是个方法,在调用时需要写成component()让其执行
在子组件中:
{this.props.component()}获取
二、子组件向父组件传值
1、传递值
通过this.props.parentCpt.getChildData.bind(this,this.state.changeMsg);来把值传到父组件的getChildData方法中,来改变父组件的值,如附1代码。
2、父组件中获取子组件的方法或值
在父组件中的子组件标签添加ref属性:<ChildComponent ref="childCpt"/>,父组件通过this.refs来获取子组件的方法和值,见附1代码父组件中的getChildRun方法。
三、propTypes和defaultProps
defaultProps:父子组件传值中,如果父组件调用子组件的时候不给子组件传值,则可以在子组件中使用defaultProps定义的默认值。
propTypes:验证父组件传值的类型合法性。
1、defaultProps的用法
在子组件中使用子组件名称调用defaultProps添加默认值:
// 父子组件传值中defaultProps的用法
ChildComponent.defaultProps={
propsData:"父子组件传值的默认值"
}
defaultProps属性需要在组件外进行调用,写在组件(class 组件{})中会报错。
然后子组件中使用this.props.propsData调用这个默认值。具体代码见附件1中所示。
2、propTypes的用法
关于propTypes更多用法可以参见React官方文档:https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html
propTypes进行的类型检查,出于性能方面的考虑,仅在开发模式下进行检查,在JavaScript控制台将会显示警告,但是不会在页面上报错,所以开发时要看控制台中类型是否错了。需要注意的是这个检查也要写在组件外。
ChildComponent.propTypes = {
propsData:PropTypes.number.isRequired
}
此处的propsData是个字符串,这里检查是否为number则会报错,报错如下:
Warning: Failed prop type: Invalid prop `propsData` of type `string` supplied to `ChildComponent`, expected `number`.
in ChildComponent (at ParentComponent.js:43)
in ParentComponent (at App.js:25)
in div (at App.js:16)
in App (at src/index.js:8)
其中的isRequired为设置属性为必须传递的值。
下面附2为可以检查的类型。
附1:父子组件代码如下:
import React from 'react';
//引入子组件
import ChildComponent from './ChildComponent';
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
msg:"这是父组件",
data:"[父组件的数据]"
};
}
run=()=>{
alert("父组件的run方法执行")
}
getParent=()=>{
alert("获取到父组件未传递的方法")
}
getChildData=(childData)=>{
this.setState({
msg:childData
})
}
getChildRun=()=>{
this.refs.childCpt.run();
this.refs.childCpt.getParentComponent();
this.setState({
msg:this.refs.childCpt.state.msg
})
}
render() {
return (
<div>
<hr style={{border:"1px solid"}}/>
<h2>这是父组件</h2>
{/* 父组件向子组件传值,在子组件标签里设置一个属性传递,例如data,通过this.state.data获取要传递的值
父组件向子组件传方法,在子组件标签设置一个属性传递,例如run,通过this.run获取要传递的方法
将整个父组件传给子组件,在子组件标签设置一个属性传递,例如parentCpt,通过this,即整个组件
*/}
{/* 在子组件标签上添加ref,父组件通过this.refs来获取子组件的方法和值 */}
<ChildComponent ref="childCpt" data={this.state.data} run={this.run} parentCpt={this}/>
<button onClick={this.getChildRun}>父组件获取子组件的方法</button>
<br/><span>父组件当前msg值:{this.state.msg}</span>
<hr style={{border:"1px solid"}}/>
</div>
);
}
}
export default ParentComponent;
import React from 'react';
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
msg:"这是子组件",
data:"[子组件的数据]",
changeMsg:"changeMsg--->父组件值被改变"
};
}
run=()=>{
alert("子组件的run方法")
}
getParentComponent=()=>{
this.props.parentCpt.getParent();
alert("父组件里的msg--->"+this.props.parentCpt.state.msg);
alert("父组件里的msg--->"+this.props.parentCpt.state.data);
}
render() {
return (
<div>
<hr style={{border:"1px dashed"}}/>
<h2>这是子组件</h2>
{/* 父组件向子组件传值,在子组件里通过this.props来调用data */}
<span>父组件向子组件传的值:{this.props.data}</span>
{/* 父组件向子组件传方法,在子组件里通过this.props来调用run */}
<button onClick={this.props.run}>点击执行父组件的run方法</button>
{/* 父组件向子组件传整个组件,
在子组件的方法里通过this.props.parentCpt来调用getParent,
也可以调用state里的值,使用this.props.parentCpt.state */}
<button onClick={this.getParentComponent}>
点击执行未传递的父组件的getParent方法
</button>
{/* 子组件向父组件传值 */}
<button onClick={this.props.parentCpt.getChildData.bind(this,this.state.changeMsg)}>
子组件给父组件传changeMsg值
</button>
{/* 父子组件传值中的默认值defaultProps */}
<br/><span>父子组件传值中的defaultProps值:{this.props.propsData}</span>
<hr style={{border:"1px dashed"}}/>
</div>
);
}
}
// 父子组件传值中defaultProps的用法
ChildComponent.defaultProps={
propsData:"父子组件传值的默认值"
}
export default ChildComponent;
附2:propTypes可检查类型:
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,
// 一个 React 元素。
optionalElement: PropTypes.element,
// 一个 React 元素类型(即,MyComponent)。
optionalElementType: PropTypes.elementType,
// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 一个对象可以是几种类型中的任意一个类型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 可以指定一个数组由某一类型的元素组成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 可以指定一个对象由某一类型的值组成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 可以指定一个对象由特定的类型值组成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
//即在附加属性上带有警告的对象
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
写在最后:
- 如果文章中有错误或是表达不准确的地方,欢迎大家评论中指正,以便我完善。
- 文章我也会根据所学到新的知识不断更新。
网友评论