前言
接着前一篇继续学习React组件化
React(03):React中的JSX语法
正文
什么是组件化: 是从 UI 界面视图的角度 来进行分析的;把一些可复用的UI元素,抽离为单独的组件;便于项目的维护和开发;
React认为一个组件应该具有以下特征:
- 可组合(Composeable):一个组件易于和其他组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件用于(own)他创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件;
- 可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个UI场景;
- 可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;
React允许将代码封装成组件(Component),然后像插入普通HTML标签一样,在网页中插入这个组件。
一、React创建与引用组件
1.1 单个组件
- 使用function创建函数式组件
function Hello(props) {
return <h1>这是 Hello 组件 --- {props.name} --- {props.age} </h1>
}
ReactDOM.render(
<Hello name="小明" age="28"/>,,
document.getElementById('example')
)
特点:它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到state状态的操作,组件不能访问this对象,不能访问生命周期方法;
- 使用class创建组件
class HelloMsg extends React.Component {
render() {
return <h1>组件测试,父组件传值={this.props.name}</h1>
}
}
ReactDOM.render(
<HelloMsg name="小明" />,
document.getElementById('example')
)
特点:用class创建的组件有状态,组件能访问this对象,可以访问生命周期方法;
1.2 多个组件组合
function Hello(props) {
return <h1>这是 Hello 组件 --- {props.name} --- {props.age} </h1>
}
class HelloMsg extends React.Component {
render() {
return <h1>class组件测试,父组件传值={this.props.name}</h1>
}
}
function App(){
return(
<div>
<Hello name="小明" age="28"/>
<HelloMsg name="小红" age="18"/>
<Hello name="小新" age="08"/>
</div>
)
}
ReactDOM.render(
<App/>,
document.getElementById('example3')
)
1.3 两种创造组件的区别
- 用构造函数创建的组件没有状态。
- 用class创建的组件有状态。
- 两种组件的本质的区别为state属性。State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。
案例:demo03
二、组件之间的传值
先来个案例,从案例中分析组件之间的传值:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="js/react.development.js"></script>
<script src="js/react-dom.development.js"></script>
<script src="js/babel.min.js"></script>
<title>组件之间的传值</title>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
// 函数
function Hello(props) {
return (
<div>
<div>这是 Hello 函数组件 --- {props.name} --- {props.age}岁 </div>
<p>我还想拿到HelloMsg组件的值: {props.helloMsg || '还没有传递过来'}</p>
父组件给的函数:{props.handleSignUp()}
</div>
)
}
// class
class HelloMsg extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: '子组件的消息',
name: '李小黑',
age: 100,
helloMsg:'啦啦啦,你好啊'
};
}
handleChange=()=>{
this.props.changeMsg(this.state)
}
render() {
return (
<div>
<p>这是HelloMsg组件,父组件传来的值--{this.props.data.msg}: 我爸爸是:{this.props.data.name}--他今年{this.props.data.age}岁</p>
<button onClick={this.handleChange}>点击子组件更改父组件参数,年龄去增加</button>
{this.props.handleSignUp()}
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
// 改变内部thisde指向
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {
msg: '内部消息',
name: 'Jcat_李小黑',
age: 88,
};
}
// 改变内部thisde指向
changeMsg=(child)=>{
// setState方法,修改msg的值,值是由child里面传过来的,单项数据流
this.setState({age:child.age++});
this.setState({helloChildMsg:child.helloMsg});
}
handleSignUp() {
console.log(`你好, ${this.state.name}!`);
return (
<h1>你好, {this.state.name}</h1>
)
}
render() {
return (
<div className="app">
{this.handleSignUp()}
<hr/>
<p>这里是父组件的页面,我是{this.state.name},拥有的消息是:{this.state.msg}</p>
<p><b>我今年:{this.state.age}岁</b></p>
<p>子组件HelloMsg给我的信息:{this.state.helloChildMsg || '还没有传递过来'}</p>
<hr/>
<HelloMsg data={this.state} handleSignUp={this.handleSignUp} changeMsg={this.changeMsg} />
<hr/>
<Hello handleSignUp={this.handleSignUp} name={this.state.name} age={this.state.age} helloMsg={this.state.helloChildMsg}/>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('example')
)
</script>
</body>
</html>
案例分析:
- 父组件:App
- class子组件:HelloMsg
- 函数式子组件:Hello
首先要知道React的组件间通讯是单向的。
数组必须是由父级传到子级或者子级传递给父级层层传递。
如果要给兄弟级的组件传递数据,那么就要先传递给父级而后在传递给你要传递到的组件位置。
2.1 父组件给子组件传值
传递参数
- App组件向子组件传值时,父组件将参数传递在标签上;
render() {
return (
<div className="app">
<HelloMsg data={this.state} />
<Hello name={this.state.name} age={this.state.age} helloMsg={this.state.helloChildMsg}/>
</div>
)
}
- 构造函数组件HelloMsg,需要在构造函数的参数列表中使用
props,{this.props.data.msg}
来接收;
render() {
return (
<div>
<p>这是HelloMsg组件,父组件传来的值--{this.props.data.msg}: 我爸爸是:{this.props.data.name}--他今年{this.props.data.age}岁</p>
</div>
)
}
- 函数式组件Hello中使用形参
props
来接收;
function Hello(props) {
return (
<div>
<div>这是 Hello 函数组件 --- {props.name} --- {props.age}岁 </div>
</div>
)
}
传递函数方法
- App父组件传递函数,写到标签上:
render() {
return (
<div className="app">
<HelloMsg handleSignUp={this.handleSignUp} />
<Hello handleSignUp={this.handleSignUp}/>
</div>
)
}
- 构造函数组件HelloMsg也是使用
this.props.handleSignUp()
接收
render() {
return (
<div>
{this.props.handleSignUp()}
</div>
)
}
- 函数式组件Hello,没有状态,也没有生命周期,所以只能接收,不能改变函数值,使用形参
props
来接收;
function Hello(props) {
return (
<div>
父组件给的函数:{props.handleSignUp()}
</div>
)
}
小结
- 父组件将参数传递写在标签上,子组件都是使用props接收参数;
- props只能接收参数,不能修改参数,修改参数要接收到值后使用setState去修改;
- class函数内部this指向问题,需要改变this的指向;
// 方法1:es6的写法
handleChange=()=>{
this.props.changeMsg(this.state)
}
// 方法2: 使用bind 改变内部this指向
constructor(props) {
super(props);
this.handleSignUp = this.handleSignUp.bind(this);
}
// 方法3: 在调用的时候使用箭头函数调用
class Test extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
return (
<button onClick={() => this.handleClick()}>
点击
</button>
);
}
}
2.2 子组件向父组件之间的传值
- 在父组件内设置修改参数的函数
changeMsg=(child)=>{
// setState方法,修改msg的值,值是由child里面传过来的,单项数据流
this.setState({age:child.age++});
this.setState({helloChildMsg:child.helloMsg});
}
- 子组件接收方法,并生成函数;
handleChange=()=>{
this.props.changeMsg(this.state)
}
- 子组件内部调用方法
render() {
return (
<div>
<button onClick={this.handleChange}>点击子组件更改父组件参数,年龄去增加</button>
</div>
)
}
- 父组件接收变动的参数
render() {
return (
<div>
<p>子组件HelloMsg给我的信息:{this.state.helloChildMsg || '还没有传递过来'}</p>
</div>
)
}
2.2 同级别的组件间传值
-
采用props传值
上述代码中的
helloChildMsg
HelloMsg组件传给App组件,App组件再传给Hello组件,这种方式比较麻烦; -
使用全局状态管理Redux (单开文章去讲)
三、其他注意事项
- 组件名称必须以大写字母开头。
- 不论是 Vue 还是 React,组件中的 props 永远都是只读的;不能被重新赋值。
- Fragment,如果你不想让你的组件最外层有标签包裹的话可以使用Fragment将你的组件包裹起来,它不会渲染。
- 组件只能包含一个根节点。
- 尽量使用函数式组件,保持简洁和无状态。
- 必须要向外return一个合法的JSX创建的虚拟DOM。
结语
以上就是React中组件化及组件之间的传值;
其他博文请移步React专栏
如果本文对你有帮助的话,请不要忘记给我点赞打call哦~o( ̄▽ ̄)do
有问题留言 over~