React入门(四)之组件传值

一、官方脚手架使用

之前我们已经说过脚手架的安装,今天再详细介绍一下脚手架的安装及使用。

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

安装包准备好了,点击下载!提取码 hhhh

安装步骤:

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>
    )
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React 中,子组件向父组件传值的常用方式是通过回调函数。下面是一个简单的示例,演示了子组件向父组件传递值的过程: 父组件: ```jsx import React, { useState } from 'react'; import ChildComponent from './ChildComponent'; const ParentComponent = () => { const [valueFromChild, setValueFromChild] = useState(''); const handleChildValue = (value) => { setValueFromChild(value); }; return ( <div> <h2>Value from child: {valueFromChild}</h2> <ChildComponent onChildValue={handleChildValue} /> </div> ); }; export default ParentComponent; ``` 子组件: ```jsx import React, { useState } from 'react'; const ChildComponent = ({ onChildValue }) => { const [inputValue, setInputValue] = useState(''); const handleChange = (event) => { setInputValue(event.target.value); }; const handleButtonClick = () => { onChildValue(inputValue); setInputValue(''); }; return ( <div> <input type="text" value={inputValue} onChange={handleChange} /> <button onClick={handleButtonClick}>Submit</button> </div> ); }; export default ChildComponent; ``` 在这个示例中,父组件包含一个状态 `valueFromChild`,子组件包含一个输入框和一个按钮。当用户在子组件的输入框中输入文本并点击按钮时,子组件会调用父组件传递的回调函数 `onChildValue`,将输入的值作为参数传递给父组件。父组件接收到这个值后,更新自己的状态 `valueFromChild`,并将其展示在页面上。 通过这种方式,子组件可以将数据传递给父组件,实现了子向父的值传递。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值