摸着那么多鱼,第一次写文章,哪里表述有问题,或者理解不到位,还请不吝赐教。
react学习笔记,记录我在开发和学习过程中遇到的问题和知识点。
2013年5月Facebook推出了React.js开源软件前端框架,函数式编程,是使用人数最多的前端框架,也拥有最健全的文档和完善的社区。
16版本之后的react叫做 react fiber
一、开发环境准备
- 引入.js文件来使用React
- 通过脚手架工具来编码,但是最终代码不能运行,需要通过webpack等来编译
(官方提供的脚手架工具 Create-react-app )
1.如何使用脚手架工具?
- 下载node.js , 进入官方网站
node -v //node版本号
npm -v //npm 版本号
2.使用脚手架工具创建一个项目
打开命令行工具,依次执行命令
npx create-react-app my-app //创建项目
cd my-app //进入项目
npm start //运行项目
正常情况下就会在浏览器中弹出以下页面,说明项目运行成功
3.运行项目
安装依赖包,在命令行中输入:
yarn install
然后重新启动npm start
或者yarn start
4.工程目录
build //打包之后自动生成的目录
public-- //生成的页面内容
| favicon.ico
| index.html
| manifest.json //不需要,可以删除
src----- //放置的是项目的源代码
| index.js //入口的js文件,放置整个项目需要引入的第三方模块或者文件
| index.css //项目页面的全局css样式
| App.js //负责往页面渲染一些内容
| App.css //项目页面的css样式
| serviceWorker //PWA的一些内容
|
|
node_modules //项目中需要的第三方模块
.gitgnore //这里面的内容不会上传到github 上
package.json //对项目的配置进行说明性的东西,版本和和第三方模块等,以及start,npm run build进行项目打包
README.md //对文件的说明描述
yarn lock //放置整个项目依赖的第三方模块的版本信息,不需要做任何修改,放在这里就可以
可以在index.js文件中引入css文件
**index.js**
//引入了两个第三方模块
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css' //可以再index.js中引入css样式文件
import App from './App.js' //在index.js中引入App.js,才能在浏览器渲染出App.js中写出的内容
//App里面的内容,通过这行代码挂载到页面id为root的标签下
ReactDOM.render(<App />,document.getElementById('root));
App.js中也可以引入css和svg
**App.js**
import logo from './logo.svg';
import './App.css';
//通过语法渲染内容
function App() {
return (
<div>
hello world
</div>
);
}
二、React 组件
(使用create-react-app脚手架工具创建项目时,会判断当前环境是否有yarn这个工具,如果有的话就会用yarn进行依赖包的安装,生成yarn.lock文件;如果没有的话就会用npm进行安装,生成package-lock.json文件)
组件就是页面上的一部分,一个网页可以分成很多个组件,每个组件又可以拆分成一个小组件
我们可以把App.js叫做一个组件,在index.js中引入了react的组件,就是把react这个组件渲染到页面上的root元素之中
1.React 模块的作用
必须引入React这个模块,引入这个模块的作用就是解析JSX语法,如果没有引入,浏览器就会报错,因为识别不出来这个语法
import React from 'react'
//JSX语法
ReactDOM.render(<App />, document.getElementById('root')
);
假如没有引入React这个模块,就会出现下面这种情况
2.Conponent 模块
这几行被注释掉的代码的缩写相当于第一行代码,实际操作中直接写缩写后的import React, {Conponent } from 'react';
**App.js**
import React, {Conponent } from 'react';
// import { Component } from 'react';
// import React from 'react';
// const { Component } = React;
// const Component = React.Component
class App extends Component {
//render函数决定了往页面上渲染的是什么内容
render() {
return (
<div>
hello world
</div>
);
}
}
export default App;
3.引入多个组件
现在我们要引入App.js和Test.js两个组件到index.js当中去
**index.js**
import App from './App';
import Test from './Test';
//JSX语法
ReactDOM.render(<div><App /><Test /></div>, document.getElementById('root')
//因为ReactDOM.render语法只能解析一个标签,所以把<App />和<Test />放在一个div当中,让react去解析这一个div就可以
4、组件
JSX语法里面,有两种类型的标签
1.普通的html标签
可以看到这种类型的标签div
都是小写的
render() {
return (
<div>
hello world
</div>
);
}
2.组件标签
可以看到App标签
首字母是大写的,所以我们在创建组件的时候直接以大写字母开头
ReactDOM.render(<App />,document.getElementById('root'));
通过判断字母大小写我们可以分辨出普通html标签和组件标签
三、使用React编写ToDoList功能
我们来看一下基本的TodoList组件内容
**TodoList.js**
import React, { Component } from 'react';
class TodoList extends Component {
render() {
return (
<div>
<input />
<ul>
<li>learn React</li>
<li>learn Component</li>
</ul>
</div>
);
}
}
// 导出组件
export default TodoList;
**index.js**
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
ReactDOM.render(<TodoList />,document.getElementById('root');
然后打开浏览器看一下html结构
能够看到input和ul外层还包裹着一层div,在这层div外部才是root,在有些情况,我们不需要这层多余的div,想让input和ul直接放到root下面,但是如果直接去掉TodoList里面的div,会出现报错显示无法解析,因为render下面只能有一个标签
react16提供了一个占位符 Fragment
,他就是一个占位的组件,并不会生成标签,所以帮助我们解决报错问题而不会生成任何标签,非常适合这种使用情况
**TodoList**
import React, { Component, Fragment } from 'react';
class TodoList extends Component {
render() {
return (
<Fragment>
<input />
<ul>
<li>learn React</li>
<li>learn Component</li>
</ul>
</Fragment>
);
}
}
// 导出组件
export default TodoList;
打开浏览器看一下html结构
页面没有变化,和原来一样,但是dom结构已经精简了,达到了我们预期的要求
四、JSX语法
1.JSX基本语法
在JSX中嵌入一个表达式,首先声明一个name
变量
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
... 甚至可以嵌入一个函数表达式
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
在formatName(user)
调用变量user
的属性,并且将formatName(user)
放置在element
中去,最后在ReactDOM.render
中引入
并且在JSX中可以包含很多子标签,唯一要注意的是,不管有多少子标签,但是只能存在一个父标签
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
JSX表示对象
可以使用React.createElement()
进行函数调用
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
完全等价于:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
2.元素渲染
将一个react元素
渲染到dom节点中去,需要传入ReactDOM.render()
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
3.更新已渲染的元素
react元素
是一个不可变对象,无法更改它的子元素,想要更改的话,需要创建一个全新的元素传入ReactDOM.render()
据一个计时器的例子
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
注意:直接
new Date()
是一个变量,无法显示在页面的节点中,只有通过toLocaleTimeString()
当法将其转化为字符串才可以显示
这个例子,setInterval
每秒会调用一次,因此在页面上,会显示每秒的时间
五、生命周期
先上一张生命周期图示
当Clock
组件第一次被渲染到DOM中的时候,就为其设置一个计时器。这在 React 中被称为挂载(mount)
。
同时,当DOM中Clock
组件被删除的时候,应该清除计时器。这在 React 中被称为卸载(unmount)
。
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}