react中文官网:https://zh-hans.reactjs.org/
- React 简介
- 安装
- React文件结构和JSX语法
- 组件
- React State(状态)
- React Props
- 事件处理
- setState 改变react状态
- 动态的添加更改class
- 添加style
- React 条件渲染
- 列表渲染
- React Refs
- 组件生命周期
- 子组件调用父组件方法|向父组件传递参数
- todolist案例
1. React 简介
React 是一个用于构建用户界面的 JAVASCRIPT 库。
React 主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。
React 特点
- 1.声明式设计 −React采用声明范式,可以轻松描述应用。
- 2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
- 3.灵活 −React可以与已知的库或框架很好地配合。
- 4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
- 5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
- 6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
2. 安装
- 安装 node.js
- 安装 create-react-app
这里介绍两种方式,习惯用哪个你自己选
第一种
npm install -g create-react-app ------全局安装create-react-app脚手架
create-react-app myapp
第二种
npx create-react-app myapp
注意⚠️ : npx不是拼写错误,它是npm5.2+ 附带的 package运行工具
上述代码的myapp是项目名,可以自定义
启动项目
cd myreact
yarn start
// npm run start
如果安装了 yarn 优先使用 yarn start
也可以使用 npm run start 启动项目
默认项目地址:http://localhost:3000/
项目目录结构介绍
或者
3 . React文件结构和JSX语法
a. 第一个react项目
打开 src/App.js 删除默认代码 得到 hello react
import React, { Component } from 'react';
//导入React和 React.Component
class App extends Component {
// App根组件继承 React.compoent
render() {
// 渲染 并返回一段html结构
return (
<div className="App">
<h1>你好react</h1>
</div>
);
}
}
export default App;
//导出默认 App根组件
<div id="demoReact"></div>
<script type="text/babel">
let myDom=<h1>你好世界</h1>
ReactDom.render(myDom,document.getElemenById("demoReact"));
</script>
b. JSX语法
JSX 是一个看起来很像 html 的 JavaScript 语法扩展。
js和html混合
1. 只能有一个根节点
return (
<div className="App">
<h1>你好react</h1>
</div>
);
// Classname="App" 就是根节点
2. 可以执行javascript表达式 {}
{1+1}
{i == 1 ? '对的!' : '错误的'}
3. 类名class 变成 className
<style>
.App{ }
</style>
<div className="App"> xxx </div>
4. 行内样式 展开
var myStyle = {
"font-size": "14px",
"color": "#FF0000"
}
return (
<div className="App">
<h1 style={myStyle}>你好react</h1>
</div>
);
5.注释 '' {/* 注释 */} ''
6. 数组里面可以直接写html节点
var arr = [
<h1>组件渲染</h1>,
<h1>虚拟dom</h1>
]
return (
<div className="App">{arr}</div>
);
7. 列表案例
8. 遍历对象
4. 组件
- 函数组件/无状态组件
- 类组件
什么是组件:
高耦合低内聚 : 高耦合就是把逻辑紧密的内容放在一个组件当中,低内聚就是把不同组件的依赖关系尽量弱化,每个组件尽量独立起来
raact组件分为3个部分,1. 属性:props 2. 状态 state 3. 生命周期
可以这么说,一个 React 应用就是构建在 React 组件之上的。
VScode插件:
- Simple React Snippets
- React Native Tools
a. 创建组件 Child.js
import React,{Component} from 'react'
export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子组件</h1>
<hr/>
</div>
);
}
}
b. 调用组件 App.js
import React, { Component } from 'react';
import Child from './components/Child.js' //01. 导入组件
// 导入组件
class App extends Component {
render() {
return (
<div className="App">
<Child/> //02 使用组件
<h1>App根组件</h1>
</div>
);
}
}
export default App;
//导出默认 App根组件
函数组件
<div id="demoReact">
</div>
<script type="text/babel">
function MyCom(){
return(
<div>我是一个函数组件/无状态组件</div>
)
}
let com = <div> //调用组件
<MyCom/>
<MyCom></MyCom>
</div>
ReactDOM.render(com,document.getElementById("demoReact"));
</script>
父子
function MyComA(){
return(
<h1>我是第1个组件</h1>
)
}
function MyComB(){
return(
<h1>我是第2个组件</h1>
)
}
function MyComC(){
return(
<h1>我是第3个组件</h1>
)
}
function Com(){
return(
<div>
<MyComA/>
<MyComB/>
<MyComC/>
</div>
)
}
ReactDOM.render(<Com/>,document.getElementById("demoReact"));
类组件
<div id="demoReact">
</div>
<script type="text/babel">
function MyCom extends React.Component{
render(){
return(
<div>我是类组件</div>
)
}
}
let com = <MyCom/>
ReactDOM.render(com,document.getElementById("demoReact"));
</script>
c. 组件插槽
app.js
import React, { Component, Children } from 'react';
import Child from './components/Child/index.js'
// 导入组件
class App extends Component {
render() {
return (
<div className="App">
<Child><p>插槽</p></Child>
<MyTag>love</MyTag>
</div>
);
}
}
export default App;
//导出默认 App根组件
function MyTag({children}){
//函数组件
return(<h3>函数组件{children}</h3>)
}
index.js
import React,{Component} from 'react'
export default class Child extends Component{
constructor(props){
super(props);
}
render(){
return (
<div className="child">
child内容{this.props.children}
</div>
);
}
}
5. React State(状态)
state 是组件的当前状态,可以把组件简单看成一个“状态机”,根据状态 state 呈现不同的 UI 展示。 一旦状态(数据)更改,组件就会自动调用 render 重新渲染 UI,这个更改的动作会通过 this.setState 方法来触发。
初始化组件 state
添加一个类构造函数来初始化状态 this.state
Child/index.js
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state={name:"mumu",age:18}
}
render() {
return (
<div className="App">
大家好我是{this.state.name}今年{this.state.age}岁了
</div>
);
}
}
export default App;
6. React Props
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
传递prop给子组件
App.js
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
render() {
return (
<div className="App">
<Child name="mumu"> </Child>
<Child name="小明"></Child>
<Child ></Child>
</div>
);
}
}
export default App;
Child.js
import React,{Component} from 'react'
export default class Child extends Component{
constructor(props){
super(props);
this.state = {num:1}
}
render(){
return (
<div className="child">
<h1>我是子组件 我的名字是{this.props.name}</h1>
<hr/>
</div>
);
}
}
Child.defaultProps = {
name:"保密"
}
// props 默认属性值
7. 事件处理
React 元素的事件处理和 DOM 元素类似
React 事件绑定属性的命名采用驼峰式写法,而不是小写。
如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
javascript写法
<button onclick="showMsg()">
按钮
</button>
react写法
<button onClick={showMsg}">
按钮
</button>
完整react代码
import React, { Component } from 'react';
class App extends Component {
showMsg(){
alert("来自react问候!");
}
render() {
return (
<div className="App">
<button onClick={this.showMsg}>按钮</button>
</div>
);
}
}
export default App;
8. setState 改变react状态
用箭头函数是为了保证函数里面this的正确指向br 你也可以用bind方法
按钮加减案例
import React,{Component, Children} from 'react'
export default class Child extends Component{
constructor(props){
super(props);
this.state = {num:1,name:'王大锤'}
}
addNum(n){
let num = this.state.num+n;
this.setState({num:num})
}
render(){
return (
<div className="child">
child内容<br/>
今年我{this.props.age}岁了<br/>
{this.state.name}<br/>
<button onClick={this.addNum.bind(this,2)}>{this.state.num}</button>
<button onClick={()=>this.addNum(-2)}>{this.state.num}</button>
{/*bind(this)指执行addNum让addNum里面的this为当前组件*/}
</div>
);
}
}
React 表单双向绑定
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {num:1}
}
changeNum(e){
this.setState({num:e.target.value})
}
render() {
return (
<div className="App">
<input type="text" value={this.state.num} onChange={this.changeNum.bind(this)}/>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default App;
9. 动态的添加更改class
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {bg:'red'}
}
changeClass(e){
this.setState(pre=>{
return ({bg:pre.bg==='red'?'blue':'red'});
})
}
render() {
return (
<div className="App">
<button className={this.state.bg} onClick={this.changeClass.bind(this)}>按钮</button>
</div>
);
}
}
export default App;
10. 添加style
render() {
var css = {
borderRadius:"6px",
padding:"8px 16px",
color:'#fff',
background:'blue'
}
return (
<div className="App">
<button style={css}>按钮</button>
</div>
);
}
}
11. React 条件渲染
条件性地渲染一块内容
三目运算符号
render() {
var isLogin = true;
return (
<div className="App">
{isLogin?'欢迎您回来主人':'请登陆'}
</div>
);
}
&&运算符
在 JavaScript 中,true && expression 总是返回 expression,而 false && expression 总是返回 false。
因此,如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。
render() {
var isLogin = false;
return (
<div className="App">
{isLogin &&'欢迎您回来主人'}
</div>
);
}
12. 列表渲染
我们可以使用 JavaScript 的 map() 方法来创建列表。
完整代码
import React, { Component } from 'react';
class App extends Component {
constructor(props) { //初始化列表数据
super(props);
this.state={
list:[{name:'vue'},{name:'react'},{name:'angular'}]
}
}
render() {
return (
<div className="App">
{this.state.list.map(
(item,index)=>{
return (
<div key={index}>{item.name}</div>
)
}
)}
</div>
);
}
}
export default App;
Key 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key:
元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:
13. React Refs
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。
你可以通过使用 this 来获取当前 React 组件,或使用 ref 来获取组件的引用
import React, { Component } from 'react';
class App extends Component {
getFocus(){
this.refs.inp.focus();
}
render() {
return (
<div className="App">
<input type="text" ref="inp" />
<button onClick={this.getFocus.bind(this)}>获取焦点</button>
</div>
);
}
}
export default App;
我们也可以使用 getDOMNode()方法获取DOM元素
14. 组件生命周期
一般来说,一个组件类由 extends Component
创建,并且提供一个 render
方法以及其他可选的生命周期函数、组件相关的事件或方法来定义。
一个简单的例子:
import React, { Component } from 'react';
class App extends Component {
getFocus(){
this.refs.inp.focus();
}
render() {
return (
<div className="App">
<input type="text" ref="inp" />
<button onClick={this.getFocus.bind(this)}>获取焦点</button>
</div>
);
}
}
export default App;
getInitialState
初始化 this.state
的值,只在组件装载之前调用一次。
如果是使用 ES6 的语法,你也可以在构造函数中初始化状态,比如:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { num:1 };
}
render() {
// ...
}
}
getDefaultProps
只在组件创建时调用一次并缓存返回的对象(即在 React.createClass
之后就会调用)。
因为这个方法在实例初始化之前调用,所以在这个方法里面不能依赖 this
获取到这个组件的实例。
在组件装载之后,这个方法缓存的结果会用来保证访问 this.props
的属性时,当这个属性没有在父组件中传入(在这个组件的 JSX 属性里设置),也总是有值的。
如果是使用 ES6 语法,可以直接定义 defaultProps
这个类属性来替代,这样能更直观的知道 default props 是预先定义好的对象值:
Child.defaultProps = { name: '保密' };
render
必须
组装生成这个组件的 HTML 结构(使用原生 HTML 标签或者子组件),也可以返回 null
或者 false
,这时候 ReactDOM.findDOMNode(this)
会返回 null
。
生命周期函数
装载组件触发
componentWillMount
只会在装载之前调用一次,在 render
之前调用,你可以在这个方法里面调用 setState
改变状态,并且不会导致额外调用一次 render
componentDidMount
只会在装载完成之后调用一次,在 render
之后调用,从这里开始可以通过 ReactDOM.findDOMNode(this)
获取到组件的 DOM 节点。
如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
更新组件触发
这些方法不会在首次 render
组件的周期调用
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
卸载组件触发
componentWillUnmount
更多关于组件相关的方法说明,参见:
完整的代码
import React, {Component } from 'react'
export default class Child extends Component {
constructor(props){
// 组件初始化
super(props);
this.state={date:new Date(),flag:true}
}
// 第一次 渲染完毕 适合 setTimeout interval ajax
componentDidMount(){
this.Id = setInterval(()=>{
this.setState({date:new Date()});
},1000)
}
componentDidUpdate(){
console.log("组件更新");
}
// 组件卸载调用
componentWillUnmount(){
clearInterval(this.Id);
}
switchHd(){
this.setState({flag:!this.state.flag});
}
render() {
return (
<div className="child">
<p>{this.state.flag?<h1>我喜欢冬天的雪</h1>:<h1>我喜欢夏天的风</h1> }</p>
<button onClick={this.switchHd.bind(this)}>切换</button>
</div>
)
}
}
15.子组件调用父组件方法|向父组件传递参数
父亲传一个函数props
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
showMsg(msg){
alert(msg);
}
render() {
return (
<div className="App">
<Child name="kangkang" fun={this.showMsg}></Child>
</div>
);
}
}
export default App;
子组件在箭头函数执行props
import React,{Component} from 'react'
export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子组件 我的名字是{this.props.name}</h1>
<button onClick={()=>{this.props.fun('我爱我的祖国')}}>调用父亲函数方法</button>
<hr/>
</div>
);
}
}
16. todolist案例
import React from 'react';
import './App.css';
import {ToDo,Child} from './components'
// 导入todo组件
class App extends React.Component {
constructor(props) {
super(props);
this.state = { msg:'todolist' }
}
changeIt(str){
alert(str);
this.setState({msg:str})
}
render() {
return (
<div className="App" >
<h1>{this.state.msg}</h1>
<ToDo></ToDo>
<Child msg={this.state.msg}></Child>
{/* 使用todo组件 */}
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import './normalize.css'
import './App.css';
class App extends Component {
constructor(props){
super(props);
this.state = {current:'msg',list:[{name:'vue', done:false}, {name:'react', done:false}, {name:'angular', done:true}]}
}
changeHd(e){
// console.log(e.target.value);
this.setState({current:e.target.value})
// react 不会自动更新 手动设置 current的更新
}
addList(){
let oList = this.state.list;
oList.unshift({name:this.state.current, done:false});
this.setState({list:oList,current:''});
}
removeList(item){
let oList = this.state.list;
let index = oList.indexOf(item);
oList.splice(index, 1);
this.setState({list: oList});
}
doneList(item,flag){
let oList = this.state.list;
item.done = flag;
this.setState({list: oList});
}
render() {
return (
<div className="app p15 mt15">
<h1>我的学习清单</h1>
<div className="mt30 row">
<div className="col-80">
<input
type="text"
value={this.state.current}
onChange={this.changeHd.bind(this)}
/>
</div>
<div className="col-20">
<button className="button button-primary" onClick={this.addList.bind(this)}>添加</button>
</div>
</div>
<div className="mt30">未完成</div>
<ul className="mt15">
{ this.state.list.map(
(item, index) => {
if(!item.done){
return (
<li className="item" key={index}>
<span>{item.name}</span>
<button className="button button-clear text-center r" onClick={this.removeList.bind(this,item)}>×</button>
<button className="button button-success button-m button-outline text-center r" onClick={this.doneList.bind(this,item,true)}>完成</button>
</li>
)
}
}
)}
</ul>
<div className="mt30">已完成</div>
<ul className="mt15">
{ this.state.list.map(
// => 返回的内容
// =>() 返回的对象 jxs 格式 ()代表返回一个单一的节点
// =>{ 可以执行一些额为代码 return 返回内容}
(item, index) => {
if(item.done){
return (
<li className="item" key={index}>
<span>{item.name}</span>
<button className="button button-clear text-center r" onClick={this.removeList.bind(this,item)}>×</button>
<button className="button button-outline button-m text-center r" onClick={this.doneList.bind(this,item,false)}>取消</button>
</li>
)
}
}
)}
</ul>
</div>
);
}
}
export default App;
import React, { Component } from 'react';
class ToDo extends Component {
constructor(props) {
super(props);
this.state = {
current:'',
list:[{name:'学习vue',done:true},{name:'学习React',done:false}],
key:'all',
filterList:[{name:'学习vue',done:true},{name:'学习React',done:false}],
// 初始化 filterList和list一致
}
// 设置默认的过滤后列表为全部
// current 当前input的内容
// list 清单列表初始内容
// key 过滤的条件
// filterList 过滤后的列表
}
changeFilterList(str){
this.setState({key:str});
let flist = [];
if(str==='all'){
flist = this.state.list;
// 如果是全部直接返回list
}else if(str==='done'){
flist = this.state.list.filter(item=>item.done)
// 如果是完成 返回已完成的list
}else if(str==='undo'){
flist = this.state.list.filter(item=>!item.done);
}
this.setState({filterList:flist});
// 更新过滤后的列表
}
addList(){
let olist = this.state.list; //获取到之前的list
olist.unshift({name:this.state.current,done:false});
// olist 从前面添加一个数据 ,默认done为false
this.setState({list:olist,current:''});
// 同时更新两个数据 list current清空
}
delItem(item){
let flag = window.confirm("您确定要删除吗?");
// 弹出确认框
if(flag){
let olist = this.state.list; // 拿到list
let ind = olist.indexOf(item); // 后去item对应下标
olist.splice(ind,1); // 从数组删除
this.setState({list:olist}) // 更新数据
}
}
ChangeDone(item){
item.done=!item.done;//让完成效果取反
let list = this.state.list; //获取的list
this.setState(list);
// 更新 list;
}
render() {
return (<div className="todo">
<p><span onClick={this.changeFilterList.bind(this,'all')}>全部</span> | <span onClick={this.changeFilterList.bind(this,'done')}>已完成</span> | <span onClick={this.changeFilterList.bind(this,'undo')}>未完成</span></p>
<input
type="text"
value={this.state.current}
onChange={e=>{this.setState({current:e.target.value})}}
onKeyUp={e=>e.keyCode===13?this.addList():''} />
<button onClick={()=>{this.addList()}}>添加</button>
{/* 表单的双向绑定 value 绑定, Input事件绑定*/}
{/* 实现添加列表 */}
{/* enter键添加 enter的keyCode是13 事件OnKeyUp */}
<div className="list">
{
this.state.filterList.map((item,index)=>{
return (<div key={index} className={item.done?'gray':''}> {/* 更具Item的done属性动态添加class */}
{item.name}
<button onClick={this.ChangeDone.bind(this,item)}>{item.done?'取消':'完成'}</button>
{/* 单击时候 修改完成状态 和按钮文字 */}
<span onClick={(e,item)=>this.delItem(item)}>×</span>
</div>)
})
}
{/* 实现完成 */}
{/* 动态class */}
{/* 删除功能 */}
{/* key 是dom识别标识符 优化渲染 */}
{/* map函数是数组映射函数 一一对应返回div标签数组 */}
</div>
</div>);
}
}
export default ToDo;
// 创建并导出todo组件