学习props
大约 7 分钟
注意
props是只读的,不可修改props的数据。props相当于只是作为父子之间参数的媒介:父组件 -> props -> 子组件
,这个过程直接传递。子组件 -> props -> 父组件
,这个过程需要子组件点击事件通知父组件改变数据。 整个过程,props只是充当传递数据的作用,不可对props直接进行修改。
父子之间传参
查看Class组件父子之间传参示例代码
父组件
import React from "react";
import ChildClass from "./components/Child-class";
export default class App extends React.Component {
state = {
arr: ["Web", "Java", "C++", "C#"],
childData: "",
};
getData(data) {
this.setState({
childData: data,
});
}
sendData2Child() {
this.setState({
arr: ["喜羊羊", "美羊羊", "沸羊羊", "慢羊羊"],
});
}
render() {
return (
<>
<h2>父组件</h2>
<p>来自子组件的数据:{this.state.childData}</p>
<button onClick={this.sendData2Child.bind(this)}>改变发送子组件的数据</button>
<hr />
<ChildClass data={this.state.arr} getData={this.getData.bind(this)}></ChildClass>
</>
);
}
}
子组件
import React from "react";
export default class ChildClassDemo extends React.Component {
sendData2Dad(str) {
this.props.getData(str);
}
render() {
return (
<>
<h2>子组件</h2>
<div>
来自父组件的数据:
<ol>
{this.props.data.map((element, index) => (
<li key={index}>{element}</li>
))}
</ol>
</div>
<button onClick={() => this.sendData2Dad("我是子组件的数据")}>向父组件传递数据</button>
</>
);
}
}
查看Hook组件父子之间传参示例代码
父组件
import { useState } from "react";
import ChildHook from "./components/Child-hook";
const App = () => {
const [arr, setArr] = useState(["Web", "Java", "C++", "C#"]);
const [str, setStr] = useState("");
const changeChildData = () => {
setArr(["喜羊羊", "美羊羊", "沸羊羊", "慢羊羊"]);
};
return (
<>
<h2>父组件Hook组件</h2>
<button onClick={changeChildData}>该变子组件的数据</button>
<p>来自子组件的数据:{str}</p>
<ChildHook data={arr} getChildData={data => setStr(data)}></ChildHook>
</>
);
};
export default App;
子组件
const ChildHookDemo = props => {
const sendData2Dad = () => {
props.getChildData("我是子组件的数据");
};
return (
<>
<h2>子组件Hook组件</h2>
<div>
来自父组件的数据:
<ol>
{props.data.map((element, index) => (
<li key={index}>{element}</li>
))}
</ol>
</div>
<button onClick={sendData2Dad}>向父组件发送数据</button>
</>
);
};
export default ChildHookDemo;
通过props实现组件复用
查看Class组件父子之间传参示例代码
父组件
import React from "react";
import ChildClass from "./components/Child-class";
export default class App extends React.Component {
state = {
arr: ["Web", "Java", "C++", "C#"],
};
render() {
return (
<>
<h2>父组件</h2>
项目一:
<ChildClass data={this.state.arr}></ChildClass>
项目二:
<ChildClass data={this.state.arr}></ChildClass>
</>
);
}
}
子组件
import React from "react";
export default class ChildClassDemo extends React.Component {
render() {
return (
<>
<ol>
{this.props.data.map((element, index) => (
<li key={index}>{element}</li>
))}
</ol>
</>
);
}
}
查看Hook组件父子之间传参示例代码
父组件
import { useState } from "react";
import ChildHook from "./components/Child-hook";
const App = () => {
const [arr, setArr] = useState(["Web", "Java", "C++", "C#"]);
return (
<>
<h2>父组件Hook组件</h2>
项目一:
<ChildHook data={arr}></ChildHook>
项目二:
<ChildHook data={arr}></ChildHook>
</>
);
};
export default App;
子组件
const ChildHookDemo = props => {
return (
<>
<ol>
{props.data.map((element, index) => (
<li key={index}>{element}</li>
))}
</ol>
</>
);
};
export default ChildHookDemo;
通过props进行状态提升
状态提升简而言之就是将共同的数据,提升到共同的父组件去管理。
官方的话就是:多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
查看Class组件父子之间传参示例代码
父组件
import React from "react";
import Child1Class from "./components/Child-class";
import Child2Class from "./components/Child2-class";
export default class App extends React.Component {
constructor() {
super();
this.state = {
count: 0,
unit: "R",
};
}
render() {
return (
<>
<h2>父组件</h2>
<Child1Class getMoney={money => this.setState({ count: money, unit: "R" })} money={this.state.unit == "R" ? this.state.count : this.state.count * 7}></Child1Class>
<Child2Class getMoney={money => this.setState({ count: money, unit: "M" })} money={this.state.unit == "M" ? this.state.count : this.state.count / 7}></Child2Class>
</>
);
}
}
子组件1
import React from "react";
export default class Child1ClassDemo extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<>
<h2>子组件Hook组件1</h2>
<label htmlFor="yuan">
人民币:
<input type="text" id="yuan" onChange={e => this.props.getMoney(e.target.value)} value={this.props.money} />
</label>
</>
);
}
}
子组件2
import React from "react";
export default class Child2Class extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<>
<h2>子组件Hook组件2</h2>
<label htmlFor="dollar">
美刀:
<input type="text" id="dollar" onChange={e => this.props.getMoney(e.target.value)} value={this.props.money} />
</label>
</>
);
}
}
查看Hook组件父子之间传参示例代码
父组件
import { useState } from "react";
import Child1Hook from "./components/Child-hook";
import Child2Hook from "./components/Child2-hook";
const App = () => {
const [money, setMoney] = useState({
count: 0, //面值
unit: "R", //R-人民币 or M-美元
});
return (
<>
<h2>父组件Hook组件</h2>
<Child1Hook getMoney={money => setMoney({ count: money, unit: "R" })} money={money.unit == "R" ? money.count : money.count * 7}></Child1Hook>
<Child2Hook getMoney={money => setMoney({ count: money, unit: "M" })} money={money.unit == "M" ? money.count : money.count / 7}></Child2Hook>
</>
);
};
export default App;
子组件1
const ChildHookDemo = props => {
return (
<>
<h2>子组件Hook组件1</h2>
<label htmlFor="yuan">
人民币:
<input type="text" id="yuan" onChange={e => props.getMoney(e.target.value)} value={props.money} />
</label>
</>
);
};
export default ChildHookDemo;
子组件2
const Child2HookDemo = props => {
return (
<>
<h2>子组件Hook组件2</h2>
<label htmlFor="dollar">
美刀:
<input type="text" id="dollar" onChange={e => props.getMoney(e.target.value)} value={props.money} />
</label>
</>
);
};
export default Child2HookDemo;
使用PropTypes进行props类型检查
使用PropTypes
进行类型检查可以增强代码的健壮性,避免不必要的报错。
前提条件:
npm i prop-types
查看Class组件父子之间传参示例代码
父组件
import React from "react";
import ChildClass from "./components/Child-class";
export default class App extends React.Component {
state = {
title: "总数",
total: 10,
};
render() {
return (
<>
<h2>父组件</h2>
{/* 子组件约束了total的数据类型为number */}
<ChildClass title={this.state.title} total={this.state.total}></ChildClass>
{/* 可以不传total,将默认为0 */}
<ChildClass title={this.state.title}></ChildClass>
{/* 子组件约束了必须要传title,不然会报错 */}
{/* <ChildClass></ChildClass> */}
</>
);
}
}
子组件
import React from "react";
import PropTypes from "prop-types";
export default class ChildClassDemo extends React.Component {
render() {
return (
<>
<p>
{this.props.title}:{this.props.total}
</p>
</>
);
}
}
//规定 total 值为number,且是必传的
ChildClassDemo.propTypes = {
title: PropTypes.string.isRequired,
total: PropTypes.number,
};
//默认值
ChildClassDemo.defaultProps = {
total: 0,
};
查看Hook组件父子之间传参示例代码
父组件
import { useState } from "react";
import ChildHook from "./components/Child-hook";
const App = () => {
const [obj, setObj] = useState({ title: "总数", total: 10 });
return (
<>
<h2>父组件Hook组件</h2>
{/* 子组件约束了total的数据类型为number */}
<ChildHook title={obj.title} total={obj.total}></ChildHook>
{/* 可以不传total,将默认为0 */}
<ChildHook title={obj.title}></ChildHook>
{/* 子组件约束了必须要传title,不然会报错 */}
{/* <ChildHook></ChildHook> */}
</>
);
};
export default App;
子组件
import PropTypes from "prop-types";
const ChildHookDemo = props => {
return (
<>
<p>
{props.title}:{props.total}
</p>
</>
);
};
//规定 total 值为number,且是必传的
ChildHookDemo.propTypes = {
title: PropTypes.string.isRequired,
total: PropTypes.number,
};
//默认值
ChildHookDemo.defaultProps = {
total: 0,
};
export default ChildHookDemo;
组合 VS 继承
在React中,并没有发现需要使用继承来构成组件层次的情况。
Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。
注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。
React中的组合类似于Vue中插槽的概念。
那么React中的组合是怎么样的?
查看Class组件父子之间传参示例代码
父组件
import React from "react";
import ChildClass from "./components/Child-class";
export default class App extends React.Component {
render() {
return (
<>
<h2>父组件</h2>
<ChildClass>我被包裹了</ChildClass>
</>
);
}
}
子组件
import React from "react";
export default class ChildClassDemo extends React.Component {
render() {
return <>{this.props.children}</>;
}
}
查看Hook组件父子之间传参示例代码
父组件
import ChildHook from "./components/Child-hook";
const App = () => {
return (
<>
<h2>父组件Hook组件</h2>
<ChildHook>
<p>我被包裹了</p>
</ChildHook>
</>
);
};
export default App;
子组件
const ChildHookDemo = props => {
return (
<>
<h2>子组件Hook</h2>
{props.children}
</>
);
};
export default ChildHookDemo;
注意点
注意标签不能重复,就上面例子:如果ChildHook
组件里包裹的有标签,那么{props.children}
外不能有标签包裹,否则是会报错的。见下错误例子。
查看错误的示例
父组件
import ChildHook from "./components/Child-hook";
const App = () => {
return (
<>
<h2>父组件Hook组件</h2>
<ChildHook>
<p>我被包裹了</p>
</ChildHook>
</>
);
};
export default App;
子组件
const ChildHookDemo = props => {
return (
<>
<h2>子组件Hook</h2>
<p>{props.children}</p>
</>
);
};
export default ChildHookDemo;
**总结错误:**上面错误示例就会报错,实际会被渲染为<p><p>我被包裹了</p></p>
,它会认为第一个<p>
是开始标签,第二个<p>
是结尾标签。 如果父组件使用子组件时,子组件内没有标签包裹,那么{props.children}
可以用标签包裹。但是如果子组件内有标签包裹,那么{props.children}
不可以用标签包裹。