写这篇文章初衷是整理一下本身这两个多月的心路历程,从刚开始 “入坑”
react
时的一脸懵,不知如何下手,到如今能够写简单的业务。之因此定义名字为“爬坑记录”,并非由于中介跌入不少坑,而是在讲述本身从彻底不了解这个框架 ,而后又一步步上道儿,我这里就称之为“爬坑”,哈哈。因此想把本身的学习过程以及爬坑记录下来,给本身往后翻阅,若有也在写react
,想交流的小伙伴,文末有微信哦,哈哈。其实从很早就想研究下react
了,只是时间上的不容许,如今终于能够腾出时间来(其实平时工做较饱和,也只能挤业余时间了)。html
------文中的示例都是本身通过实践的,如理解有误,还请告知哦!😂------vue
部分纯
react
组件示例,部分来自umi
脚手架配合dva
的项目组件示例,ui
组件是ant-design
,模版使用的是antdesign的pro-layout
现成的模版。react
具体版本号以下:ios
"@ant-design/pro-layout": "4.7.0",
"@antv/g2": "^3.5.11",
"antd": "^3.25.2",
"array-move": "^2.2.0",
"umi": "2.12.3",
"umi-plugin-react": "1.14.7",
"uuid": "^3.3.3",
"axios": "^0.19.0",
"bizcharts": "^3.5.6",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.2.0",
"dayjs": "^1.8.17",
"immutable": "^4.0.0-rc.12",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"mz-modules": "^2.1.0",
"parameter": "^3.6.0",
"prop-types": "^15.7.2",
"qrcode": "^1.4.4",
"qs": "^6.9.1",
"rc-form-hooks": "^0.0.1-alpha.22",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"swr": "^0.1.12",
复制代码
react
的生命周期如同
vue
同样,react
也是有本身的生命周期,方便咱们根据加载顺序来执行相应的操做。json
经常使用的生命周期以下:axios
在渲染前调用:
componentWillMount
数组在第一次渲染后调用:
componentDidMount
bash在组件完成更新前调用:
componentWillUpdate
微信在组件完成更新后当即调用:
componentDidUpdate
babel在组件接收到一个新的 prop (更新后)时被调用:
componentWillReceiveProps
在组件从 DOM 中移除以前马上被调用:
componentWillUnmount
加载渲染过程:
父 bcomponentWillMount => 父 render => 子 componentWillMount =>子 render => 子 componentDidMount => 父componentDidMount
复制代码
子组件经过props取值并更新过程:
子 componentWillUpdate => 父 render => 子 componentWillReceiveProps => 父 componentWillUpdate => 子 render => 子 componentDidUpdate => 父 componentDidUpdate
复制代码
单一父 / 子组件(不依赖props)更新过程:
componentWillUpdate => render => componentDidUpdate
复制代码
销毁过程:
componentWillUnmount
复制代码
let root = document.getElementById('example');
/*
* 相似vue的template ,第一个参数是插入的模版,第二个是插入的跟元素
* 在react中样式中的 class 要重命名为 className
* render 是必不可少的,用来渲染到页面上
*/
ReactDOM.render(
<h1 className="box">Hello, world!</h1>,
root
);
复制代码
效果展现:
在react中定义变量是很方便的,能够定义数组,数组中能够包含咱们的
html
标签,而后能够将变量直接带入到页面上。
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example')
let arr = [
<h1 >Hello world!</h1>,
<h2 >Hello React!</h2>,
];
// 注意,react 的变量使用的是单花括号 {}
ReactDOM.render(
<div>{arr}</div>,
root
);
</script>
复制代码
效果展现:
在React里组件都是用class来写的,React来写组件无疑是很爽的,下面咱们就来试试。
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example');
// class 的名字必须大写,并继承自 React.Component
class HelloMessage extends React.Component {
constructor(...args){
super(...args);
this.name=this.props.name
this.job=this.props.job
this.age = this.props.age
}
fn(){
return "Aaa"
}
render() {
// 变量还能够直接定义标签,style后面需跟一个{},而里面的内容须要是一个json,因此此处看起来是两个{{}}
let div =<div style={{color:'red'}}>我是div</div>
return (
<div>
// 花括号中的值还能够参与计算
姓名: {this.name}<br/>
工做: {this.job}<br/>
年龄: {this.age+3}<br/>
// 花括号不只能够输出变量,还能够输出方法
{this.fn()} <br/>
// 将标签输出到页面
{div}
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="John" job="teacher" age="18"/>,
root
);
</script>
</body>
复制代码
JSX语法容许咱们html 和 js 穿插来写,咱们来看看最经常使用的循环怎么写。
在普通(非class)组件中添加循环:
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example')
let names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name, index) {
// 循环中须要添加key值,用来保证惟一性
return <div key={index}>Hello, {name}!</div>
})
}
</div>,
root
);
</script>
</body>
复制代码
效果展现:
在class 里面写循环:
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example');
class HelloMessage extends React.Component {
constructor(...args){
super(...args)
}
render() {
let arr =[];
for(let i =0;i<5;i++){
// 注意:这里须要给每一个li 添加一个key
arr.push(<li key={i}>{i}</li>)
}
return (
<div>
<ul>{arr}</ul>
</div>
);
}
}
ReactDOM.render(
<div>
<HelloMessage />
</div>,
root
);
</script>
</body>
复制代码
效果展现:
咱们日常的开发中,有时候须要用到些公共组件,那咱们就应对其进行封装提取出来,如下是粗略版的父子组件嵌套写法
<body>
<div id="example"></div>
<script type="text/babel">
// 父组件
class Parent extends React.Component{
constructor(...args){
super(...args)
}
render(){
return(
<ul>
// 将写好的子组件嵌套进来便可
<Child/>
<Child/>
<Child/>
<Child/>
</ul>
)
}
}
// 子组件
class Child extends React.Component{
constructor(...args){
super(...args)
}
render(){
return(
<li>111</li>
)
}
}
ReactDOM.render(
<Parent />
,
document.getElementById('example')
);
</script>
</body>
复制代码
通常状况下,render 里面只会有一个最大的标签包含,若是你有两个标签,请在外面添加一个包裹标签,正确写法:
ReactDOM.render(
<div>
<Parent></Parent>
<Child></Child>
</div>,
document.getElementById('example')
);
复制代码
错误写法:
ReactDOM.render(
<Child></Child>
<Parent></Parent>
,
document.getElementById('example')
);
复制代码
在脚手架中还可用
react
中的Fragment
去充当咱们最外层的包裹层,它的好处是不会多生成一个div
import { Component, Fragment } from 'react'
class ConfigContent extends Component {
constructor(...args){
super(...args)
}
render(){
return(
<Fragment>
<Parent></Parent>
<Child></Child>
</Fragment>
)
}
}
export default ConfigContent
复制代码
组件能够写成单标签或者双标签两种形式。以下:
// 双标签
<Parent></Parent>
// 单标签
<Parent/>
复制代码
props
父组件给子组件传递参数,子组件接收,并渲染子组件: 父组件=>子组件
父组件
import { PureComponent } from "react";
import Child from "./child";
class Parent extends PureComponent {
constructor(props) {
super(props);
this.state = { id: 1 };
}
render() {
return (
<Child id={this.state.id} />
);
}
}
export default Parent;
复制代码
子组件:
import { PureComponent } from "react";
class Child extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>child-page</h1>
<p>{this.props.id}</p>
</div>
);
}
}
export default Child;
复制代码
效果展现:
子组件经过事件将子组件的值传到父组件: 子组件=>父组件
子组件:
import { Button } from "antd";
import { PureComponent } from "react";
class Child extends PureComponent {
constructor(props) {
super(props);
this.state = { a: 1 };
}
action = {
handleChange: () => {
this.props.changeEvent(`子组件定义的值:${this.state.a}`);
}
};
render() {
return (
<div>
<h1>child-page</h1>
<Button type="primary" onClick={this.action.handleChange}>
改变父组件
</Button>
</div>
);
}
}
export default Child;
复制代码
父组件:
import { PureComponent } from "react";
import { Button } from "antd";
import Child from "./child";
class Parent extends PureComponent {
constructor(props) {
super(props);
}
action = {
changeEvent: mode => {
console.log("父组件收到的值:", mode);
}
};
render() {
return (
<div>
<Child changeEvent={mode => this.action.changeEvent(mode)} />
</div>
);
}
}
export default Parent;
复制代码
点击后的效果展现:
事件是咱们在交互过程当中必不可少的,那么咱们试试看,
在react
中如何添加事件。
(1)咱们原生的添加事件的方式,采用的是小写onclick
:
<button onclick="activateLasers()">
Activate Lasers
</button>
复制代码
(2)react的添加事件,采用驼峰的方式定义onClick
:
<button onClick={activateLasers}>
Activate Lasers
</button>
复制代码
下面介绍几种在项目中添加事件的方式,你们可根据状况选择:
<body>
<div id="example"></div>
<script type="text/babel">
class Child extends React.Component {
constructor(...args){
super(...args)
this.a=[123]
}
// 直接在标签上添加
render() {
return (
<div onClick={function(){
console.log("eee")
}}>{this.a}</div>
)
}
}
ReactDOM.render(
<Child/>,
document.getElementById('example')
)
</script>
</body>
复制代码
class
组件中添加方法(须要从新绑定this):<body>
<div id="example"></div>
<script type="text/babel">
class Cmp1 extends React.Component{
constructor(...args){
super(...args)
}
fn(){
// props只读的,这里的值是不可改的,是从外面传进来的
console.log(this.props.a) // 0
}
// onClick 相似原生事件,此处bind就是把咱们的fn的this紧紧绑在组件上,此时的内部也能拿到咱们组件的this
render(){
return(
<div>
{this.props.a}
<input type="button" value="+1" onClick={this.fn.bind(this)}/>
</div>
)
}
}
ReactDOM.render(
<div>
<Cmp1 a={0}/>
</div>,
document.getElementById('example')
);
</script>
</body>
复制代码
<body>
<div id="example"></div>
<script type="text/babel">
class Child extends React.Component {
constructor(...args){
super(...args)
this.a=[123]
}
// 定义变量
action ={
fn(){
console.log(23)
}
}
// 在这里直接调用,就不用绑定this了
render() {
return (
<div onClick={this.action.fn}>{this.a}</div>
)
}
}
ReactDOM.render(
<Child/>,
document.getElementById('example')
)
</script>
</body>
复制代码
<body>
<div id="example"></div>
<script type="text/babel">
class Child extends React.Component {
constructor(...args){
super(...args)
this.a=[123]
}
fn=()=>{
console.log(23)
}
render() {
return (
<div onClick={this.fn}>{this.a}</div>
)
}
}
ReactDOM.render(
<Child/>,
document.getElementById('example')
)
</script>
</body>
复制代码
备注一下,关于事件传参的写法:
import { PureComponent } from "react";
import { Button } from "antd";
class App extends PureComponent {
constructor(props) {
super(props);
this.state = { arr: [1, 2, 3, 4] };
}
action = {
handleClick: i => {
console.log(i.target.innerHTML);
}
};
render() {
return (
<div>
{this.state.arr.map((item, index) => {
return (
<Button
key={index}
onClick={index => this.action.handleClick(index)}
>
{item}
</Button>
);
})}
</div>
);
}
}
export default App;
复制代码
效果展现:
state
制做一个 input ++ 功能
state
构造函数是惟一可以初始化this.state
的地方,接收一个对象,是可变的,能够是内部加的,也能够从外部传进来,this.setSate
是惟一改变state
的方式。
// 制做一个input ++ 功能
<body>
<div id="example"></div>
<script type="text/babel">
class Cmp1 extends React.Component{
constructor(...args){
super(...args)
this.state={a:0}
}
fn(){
// this.setSate是惟一改变state的方式
this.setState({a:this.state.a+1})
}
render(){
return(
<div>
{this.state.a}
<input type="button" value="+1" onClick={this.fn.bind(this)}/>
</div>
)
}
}
ReactDOM.render(
<div>
<Cmp1/>
</div>,
document.getElementById('example')
);
</script>
</body>
复制代码
页面效果:
咱们在跳转路由时,有时须要给跳转到到页面携带一些参数来定位页面的显示或回显数据,此小节咱们就来看看如何传参,以及入股取参。
首先咱们先拿一下props,看看都有哪些参数:
console.log(this.props);
复制代码
参数以下:
咱们来具体解析一下:
history:包含了路由push replace goBack 等方法,以及可拿到query state 等参数
history:{
location:{
pathname:'/dashboard/workplace', // url地址
search:'?name='xiaoxiao', // 拿到的是完整的参数字符串 hash:'', query:{name:'xiaoxiao'}, // 拿到参数的对象格式 state:undefined // 拿到经过state传入的参数 }, push:function push(path,state){} , // 跳转到指定路径 replace:function replace(path,state){} , // 跳转到指定路径,不会保留history goBack:function goBack(path,state){} , // 返回上一个路由地址 } 复制代码
这个location 同上面的location,可拿到query参数 以及state 参数
location:{
pathname:'/dashboard/workplace',
search:'?name='xiaoxiao', query:{name:'xiaoxiao'}, state:undefined } 复制代码
包含了具体的 url 信息,并能够拿到params的参数的值。
match:{
path:'/dashboard/workplace',
url:'/dashboard/workplace',
params:{}
}
复制代码
接下来咱们就使用:this.props.history.push
来模拟跳转,并携带参数:
经过
url
来进行传参,地址栏是可见的
⚠️注意️:刷新页面后,参数不会丢失,可传对象
A 页面:
this.props.history.push({
pathname: "/dashboard/workplace",
query: { name: "xiaoqiu" }
});
复制代码
B页面 (参数在url
里问号后显示)
http://localhost:8000/#/dashboard/workplace?name=xiaoqiu
复制代码
打印一下咱们接收到的参数:
state传参,同query差很少,只是属性不同,并且state传的参数是加密的,不会在地址栏显示
注意️:刷新页面后,参数就会丢失,可传对象
A页面:
this.props.history.push({
pathname: "/dashboard/workplace",
state: { name: "xiaoqiu" }
});
复制代码
B页面: (参数并无出如今地址栏哦!)
http://localhost:8000/#/dashboard/workplace
复制代码
打印一下咱们接收到的参数:
search
同query
参数同样是经过url
进行传输
⚠️注意️:刷新页面后,参数不会丢失,但只可传字符串,不能传输对象
A页面:
this.props.history.push({
pathname: "/dashboard/workplace",
search: "a=1&b=2"
});
复制代码
B页面
http://localhost:8000/#/dashboard/workplace?a=1&b=2
复制代码
打印一下咱们接收到的参数:
此时咱们注意到不管是经过
query
或是search
传参,返回参数时二者也同时都能取到,只是展示方式不一样。query
是以对象形式展示,search
是以字符串展示,若是你想在地址栏显示,那就用query
,若是想加密传输,那就用state
,但要注意使用state
传递参数刷新后就会丢失哦!
ref
获取组件实例经过给组件绑定ref 能够获取到整个子组件的实例,进而可传参数并调用其方法
ref
,获取当前组件的参数以及事件import { Button } from "antd";
import { PureComponent } from "react";
class Child extends PureComponent {
constructor(props) {
super(props);
this.state = { a: 1 };
}
action = {
handleChange: () => {
console.log(this.refs["button"]);
}
};
render() {
return (
<div>
<h1>child-page</h1>
<Button type="primary" onClick={this.action.handleChange} ref="button">
改变父组件按钮
</Button>
</div>
);
}
}
export default Child;
复制代码
控制台打印ref
拿到的组件参数以及方法:
react
的createRef
,拿到子组件的参数和方法import { PureComponent, createRef } from "react";
import { Button } from "antd";
import Child from "./child";
class Parent extends PureComponent {
constructor(props) {
super(props);
this.children = createRef();
this.state = { id: 1, arr: [1, 2, 3, 4] };
}
action = {
handleClick: () => {
console.log(this.children);
}
};
render() {
return (
<div>
<Button onClick={() => this.action.handleClick()}>
按钮
</Button>
子组件:
<Child ref={this.children} />
</div>
);
}
}
export default Parent;
复制代码
控制台输出子组件的值:
写到此处,并无结束哦!接下来我还会持续追加,看文章的小伙伴们能够添加一下关注哦!
做者:Christine
出处:https://juejin.im/post/5a125827518825293b4fea8a
版权全部,欢迎保留原文连接进行转载:)
复制代码
若是你对我对文章感兴趣或者有些建议想说给我听👂,也能够添加一下微信哦!
邮箱:christine_lxq@sina.com
最后:
祝各位工做顺利!
-小菜鸟Christine
复制代码