组件传值
一、官方脚手架使用
之前我们已经说过脚手架的安装,今天再详细介绍一下脚手架的安装及使用。
1.1、使用流程
1)、安装 create-react-app
npm install create-react-app -g | yarn global add create-react-app
2)、用脚手架创建 react项目
create-react-app 项目名称
注意:项目名称不能有大写字母。
3)、 启动项目:
npm start | yarn start
1.2、目录解析
创建完的项目结构如下图所示:
-
一级目录
1)node_modules:是项目依赖的模块
2)src:是程序员写代码的地方,src是source的缩写,表示源代码
3)public: 静态资源。
-
展开目录
1)index.html:是html网页,是个容器。
2)manifest.json: 生成一个网页的桌面快捷方式时,会以这个文件中的内容作为图标和文字的显示内容
3)Index.js:是主js文件,
4)Index.css:是index.js引入的css文件
5)App.js:是一个组件示例(模块),在 index.js里会引入这个组件。
6)App.css:是App.js文件引入的css文件
7)Logo.svg:是图片
8)registerServiceWorker.js:支持离线访问,
1.3、打包
npm run build | yarn build
1.4、解构出配置文件
npm run eject | yarn eject 解构出所有的配置文件 可选
1.5、调试工具,安装react-dev-tools
安装步骤:
1)、点击谷歌浏览器右上角三个点;
2)、依次点击更多工具—>扩展程序,会看到如下图:
3)、打开右上角开发者模式,将下载好的文件拖入空白处,点击确定即可。
1.6、环境配置
1、把配置解构
npm run eject | yarn eject
报git错误时:
git add . -> git commit -m 'init' -> yarn eject
报缺少babel 包: 安装一下
2、修改端口
//修改script/start.js
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3001;
3、去除eslint 警告
//config/webpack.config.js
//注释关于eslint的导入和rules规则
1.7、资源限制
-
本地资源导入(import) 不可以导入src之外的包
-
相对 指向src,绝对路径 指向了 public目录 <img src={"/img/1.jpg"} />
-
前景图片, 相对 和 绝对路径 都指向了 public目录
1.8、在脚手架里做项目的步骤
1)、创建目录
在src目录下创建以下文件夹:
-
assets :静态资源文件夹
-
components:组件文件夹
/components/a组件/ a.js 和 a.css
-
pages:页面文件夹
-
styles:样式文件夹
2)、图片文件夹
1.在public里放图片。
把图片放到public文件夹中 直接使用图片名使用(使用绝对路径,这样的图片不会打包
2.使用require引用,require(‘图片的相对路径’),Require中只能使用字符串不能使用变量,这样的图片会打包。
二、性能优化
react组件更新的时机:只要setState()被调用了,就会引起组件更新。不论数据改前改后是否一样,或者修改的数据是否在页面上呈现,都会进行更新组件。
但是vue中,数据必须在模板使用,并且数据发生变化才能引起组件的重新渲染。所以,在React里,如果要做性能优化,可以把这种无效的渲染阻止掉。
1)、shouldComponentUpdate()钩子函数
shouldComponentUpdate(nextProps, nextState){
console.log("this.state",this.state);//当前状态
console.log("nextState",nextState);//新的状态
return false;//不再渲染。
}
我们可以在这个钩子函数里return false,来跳过组件更新
2)、PureComponent
React15.3中新加了一个 PureComponent 类,只要把继承类从 Component 换成 PureComponent 即可
-
PureComponent 默认提供了一个具有浅比较的shouldComponentUpdate方法。只是比较数据是否有变化,并不会判断数据是否在页面上展示。
-
当props或者state改变时,PureComponent将对props和state进行浅比较
-
不能再重写shouldComponentUpdate
-
PureComponent只是解决了数据不变化的情况下不做再次的渲染,而不能解决是否在页面上使用。
Component和PureComponent的区别:
1)、当组件继承自 Component 时,只要setState()被调用了,就会引起组件更新。不论数据改前改后的是否一样,或者修改的数据是否在页面上呈现,都会进行更新组件。
2)、 PureComponent只能保证数据不变化的情况下不做再次的渲染。
三、组件传值
3.1、父子组件通信方式
(1) Props传递数据与Props传递方法
父组件—>子组件传递数据,用props传递数据
1)、定义组件时,声明props形参:
class Person extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
姓名:<span>{this.props.name}</span><br/>
</div>
);
}
}
2)、使用组件时,传入参数:
<Person name='张三疯' >
子组件—>父组件传递数据,用props传递方法
父组件利用props传递方法给子组件,子组件回调这个方法的同时,将数据传递进去,使得父组件的相关方法得到回调,这个时候就可以把数据从子组件传递给父组件了
//1、父组件
class App extends React.Component {
constructor(){
super();
this.state={
t:"Home"
}
}
changeData(str){
console.log("子传给了父亲:",str);
}
render = () => (
<div className="App">
<Home title={this.state.t} fn={this.changeData}/>
<My title="My"/>
</div>
)
};
//2、子组件
class Home extends React.Component {
constructor(name){
super();
this.name=name;
this.state={
msg:"hello "
}
}
render = () => (
<div>
<h1>我是{this.props.title}</h1>
<p>{this.state.msg+this.props.title}</p>
<input
type="button"
value="传给父亲"
onClick={()=>this.props.fn('HELLO dad')} />
</div>
)
}
(2) ref 标记
组件间通信除了props外还有onRef方法,不过React官方文档建议不要过度依赖ref。
思路:当在子组件中调用onRef函数时,正在调用从父组件传递的函数。this.props.onRef(this)这里的参数指向子组件本身,父组件接收该引用作为第一个参数:onRef = {ref =>(this.child = ref)}然后它使用this.child保存引用。之后,可以在父组件内访问整个子组件实例,并且可以调用子组件函数。
//子组件
class Person extends React.Component {
constructor(props) {
super(props);
this.state={
msg:"hello"
}
}
//渲染完毕
componentDidMount(){
//子组件首次渲染完毕后,把子组件传给父组件(通过props的onRef)
this.props.onRef(this);//把子组件传给父组件,注意,此处的this是子组件对象
}
render() {
return ( <div> 我是子组件</div> );
}
}
//父组件:
class Parent extends React.Component{
constructor(props){
super(props);
this.child =null;//定义了一个属性,该属性表示子组件对象
}
testRef=(ref)=>{
this.child = ref //给父组件增加属性child,child保存着子组件对象
console.log(ref) // -> 获取整个Child元素
}
handleClick=()=>{
alert(this.child.state.msg) // -> 通过this.child可以拿到child所有状态和方法
this.child.setState({
msg:"哈哈"
})
}
render(){
return (
<div>
<Person onRef={this.testRef} ></Person>
</div>
)
}
}
ReactDOM.render(<Parent />,$("box"));
3.2、非父子组件通信方式
(1)订阅发布(pubsub模块)
- 订阅: token=pubsub.subscribe(‘消息名’,回调函数(‘消息名’,数据))
- 发布: pubsub.publish(‘消息名’,数据)
- 清除指定订阅:pubsub.unsubscribe(token|‘消息名’);
- 清除所有:pubsub.unsubscribeAll()
<script src="https://unpkg.com/PubSub@3.6.0//dist/pubsub.min.js"></script>
var pubsub = new PubSub();
class MyCom1 extends React.Component{
constructor(){
super();
}
testf(){
pubsub.publish('user_add', {
firstName: 'John',
lastName: 'Doe',
email: 'johndoe@gmail.com'
});
}
render(){
return (
<div>
<p>MyCom1</p>
<input type="button" value="传递数据" onClick={()=>this.testf()} />
</div>
)
}
}
class MyCom2 extends React.Component{
constructor(){
super();
this.state={
msg:"hi"
}
//订阅
pubsub.subscribe('user_add', function (data) {
console.log('User added');
console.log('user data:', data);
});
}
render(){
return (
<div>
<h1>MyCom2</h1>
</div>
)
}
}
const jsx = <div><MyCom1/><hr/>
<MyCom2/></div>
ReactDOM.render(
jsx,
document.getElementById('box')
);
(2)状态提升
使用 react 经常会遇到几个组件需要共用状态(数据)的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。
即:把原本属于子组件的state,放在父组件里进行管理。
父组件:src/components/Parent.js
import React from "react";
import Son1 from "./Son1";
import Son2 from "./Son2";
export default class Parent extends React.Component {
constructor(props){
super(props);
this.state = {val:'默认值'};
}
tempFn(val){
console.log("tempFn");
console.log("val",val);
this.setState({
val:val
})
}
render = () => (
<div >
父组件
<hr/>
<Son1 onMyClick={(val)=>this.tempFn(val)} />
<Son2 val={this.state.val} />
</div>
)
}
Son1组件
src/components/Son1.js
export default class Son1 extends React.Component {
constructor(props){
super(props);
this.state = {
name:"我是son1"
};
}
chuan(){
this.props.onMyClick(this.state.name);
}
render = () => (
<div >
son1组件
<input type="button" value="son1传给parent" onClick={()=>{this.chuan()}} />
<hr/>
</div>
)
}
Son2组件
src/components/Son2.js
export default class Son2 extends React.Component {
constructor(props){
super(props);
this.state = {};
}
render = () => (
<div >
<p>son2组件</p>
<p>val:{this.props.val}</p>
<hr/>
</div>
)
}