React 入门,based on React.16.4.2
本次教程基于环境、使用工具以及版本:
nodejs:8.11.3
react:16.4.2
npm:6.2.0
SPA(单页应用)
create-react-app:2.0.0
1. 创建项目
1.1 - 安装脚手架create-react-app
1 npm install -g create-react-app@2.0 .0 -next.3e165448
1.2 - 创建项目
1 create-react-app react-demo
1.3 - 运行项目
2. 项目结构说明
创建好项目之后的结构目录:
其中:
为什么从项目结构中并看不出任何跟webpack相关的文件?
3. 项目解包
项目解包后的入口文件、入口函数图示:
4. JSX语法
脚手架创建的react项目中的App.js,默认使用了JSX语法
使用JSX语法需要导入 react
JSX语法与非JSX语法的对比:
Demo
Demo1 - 在JSX中,通过花括号 {} ,可以使用javascript表达式,如:
1 2 3 4 5 6 7 8 9 10 render ( ) { return ( <div className ="App" > <span > hello react.</span > <div id ="demo" > 1+1={1 + 1} //最终结果:1+1=2 </div > </div > ); }
Demo2 - JSX中无法使用 if-else,但可以使用三元表达式来代替,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 render ( ) { let isDisplayOne = true ; let one = "i am One" ; let two = "i am Two" ; return ( <div className ="App" > <span > hello react.</span > <div id ="demo" > {isDisplayOne ? one : two} //通过三元表达式代替if-else,如果?号后面的内容过多,建议抽取后通过变量赋值 </div > </div > ); }
Demo3 - JSX中,html标签内部的注释需要用花括号括起来,如:
1 2 3 4 5 6 7 8 9 10 render ( ) { return ( <div className ="App" > <span > hello react.</span > <div id ="demo" > {/* <span > test annotation</span > */} </div > </div > ); }
Demo4 - JSX中,使用数组,会将数组中的内容自动按照顺序填充到html标签中,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 render ( ) { let arr = [ {} <span style={{ color : 'blue' }}>1. hello</span>, <span style ={{ color: 'yellow ' }}> 2.world</span > ]; return ( <div className ="App" > <span > hello react.</span > <div id ="demo" > <div > {arr}</div > </div > </div > ); }
Demo5 - 在JSX中,html中的一些元素属性:如class,for,需要使用 className 和 htmlFor 来做代替,如:
1 2 3 4 5 6 7 8 render ( ) { return ( <div className ="App" > {/*以下内容最终生成的html为:<span class ="testClass" for ="using htmlFor" > hello react.</span > */} <span className ="testClass" htmlFor ="using htmlFor" > hello react.</span > </div > ); }
Demo6 - jsx中,属性事件
1 2 <button onClick="XXXXX" >button</button> 这里在定义点击事件的时候,不再是全小写的“onclick”,而是“onClick”--- C 大写。命名上,类似于camel命名
使用:
1 2 3 4 5 6 7 8 9 10 11 假设在声明了如下方法: sayHello ( ){ console .log ("say hello" ); } sayHelloTo (name ) { console .log ("hello " + name); } 通过按钮点击事件使用 sayHello方法 < div > <button onClick ={this.sayHello} > button</button > </div >
在调用方法的时候,需要注意以下几点:
若调用的方法不带参数,如 sayHello:
若调用时方法上带上了圆括号,如 onClick={this.sayHello()},则在页面加载的时候,该方法会自动执行一遍。
若调用时没有带圆括号,如 onClick={this.sayHello},则页面加载的时候,该方法不会自动执行,需要点击该按钮后才会被执行。
若调用的方法带参数,如 sayHelloTo:
若调用方式为:onClick={this.sayHelloTo(‘Lucy’)},则页面加载的时候,该方法就自动执行,且之后按钮再怎么点击也无效
若想让带参方法不自动执行,方法有两种:
1.通过箭头函数:onClick={()=>this.sayHelloTo(“Lucy”)}
2.使用bind:onClick={this.sayHelloTo.bind(this,“Lucy”)} //第一个参数表示当前指向的对象,这里传的this表示的当前js中定义的class(因为该this是JSX中的this),第二个参数开始就是调用方法的入参
5. 组件:Component
一个简单例子:在src目录中创建如下目录和文件
5.1 - 创建自定义组件:Student.js
Student.js:
1 2 3 4 5 6 import React from 'react' function student (props ){ return <div > 大家好,我是学生</div > } export default student;
5.2 - 在App.js中使用Student组件
App.js:
1 2 3 4 5 6 7 8 9 10 11 导入组件:import Student from './Components/Student/Student' ; 使用组件: render ( ) { return ( <div className ="App" htmlFor ="html for for for demo" > <Student /> <Student /> <Student /> </div > ); }
5.3 - 组件中如何传值?
5.3.1 - 通过 props
Student.js:
1 2 3 4 5 6 import React from 'react' function student (props ){ return <div > 大家好,我是学生:{props.name},班级:{props.class}</div > } export default student;
App.js
1 2 3 4 5 6 7 8 9 render ( ) { return ( <div className ="App" htmlFor ="html for for for demo" > <Student name ="A" class ="class_1" /> <Student name ="B" class ="class_2" /> <Student name ="C" class ="class_1" /> </div > ); }
5.3.2 - 通过 state
什么是 state,如何使用?
state是定义在Component中的一个属性,组件必须是class组件继承自Component
定义 state:
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class App extends Component { {} state = { students :[ {id :1 , name :"John" , class :"class_A" }, {id :2 , name :"Steve" , class :"class_C" }, {id :3 , name :"Trump" , class :"class_A" }, ] } render ( ) { return ( <div className ="App" htmlFor ="html for for for demo" > <Student name ={this.state.students[0].name} class ={this.state.students[0].class}/ > <Student name ={this.state.students[1].name} class ={this.state.students[1].class}/ > <Student name ={this.state.students[2].name} class ={this.state.students[2].class}/ > </div > ); } }
如何动态修改数据?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 changeStudent = () => { this .setState ({ students : [ { id : 1 , name : "John_______" , class : "class_A" }, { id : 2 , name : "Steve" , class : "class_C" }, { id : 3 , name : "Trump" , class : "class_A" }, ] }); } render ( ) { return ( <div className ="App" htmlFor ="html for for for demo" > <Student name ={this.state.students[0].name} class ={this.state.students[0].class} /> <Student name ={this.state.students[1].name} class ={this.state.students[1].class} /> <Student name ={this.state.students[2].name} class ={this.state.students[2].class} /> <button onClick ={this.changeStudent} > 修改</button > </div > ); }
Demo1 - 数据的双向绑定:修改年级信息
App.js
增加grade信息容器
增加输入行用于更新grade信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class App extends Component { state = { students : [ { id : 1 , name : "John" , class : "class_A" }, { id : 2 , name : "Steve" , class : "class_C" }, { id : 3 , name : "Trump" , class : "class_A" }, ], gradeInfo :"grade one" } ... changeGradeInfo = (event )=> { this .setState ({ gradeInfo :event.target .value }) } render ( ) { return ( <div className ="App" htmlFor ="html for for for demo" > <div > {this.state.gradeInfo}</div > ... <input type ="text" onChange ={ this.changeGradeInfo }> </input > <button onClick ={this.changeStudent} > 修改</button > </div > ); } }
Demo2 - 修改学生姓名
App.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class App extends Component { ... changeStudentTo = (event,id ) => { let students = this .state .students ; let index = students.findIndex (ent => ent.id ===id); console .log (index); let student = students[index]; student.name = event.target .value students[index] = student; this .setState ({ students : students }); } render ( ) { return ( <div className ="App" htmlFor ="html for for for demo" > <div > {this.state.gradeInfo}</div > <Student id ={this.state.students[0].id} onChangeStudentTo ={this.changeStudentTo} name ={this.state.students[0].name} class ={this.state.students[0].class} /> <Student id ={this.state.students[1].id} onChangeStudentTo ={this.changeStudentTo} name ={this.state.students[1].name} class ={this.state.students[1].class} /> <Student id ={this.state.students[2].id} onChangeStudentTo ={this.changeStudentTo} name ={this.state.students[2].name} class ={this.state.students[2].class} /> <input type ="text" onChange ={ this.changeGradeInfo }> </input > <button onClick ={this.changeStudent} > 修改</button > </div > ); } }
Student.js:
1 2 3 4 5 6 7 8 9 10 import React from 'react' function student (props ) { return ( <div > <div > 大家好,我是学生:{props.name},班级:{props.class}</div > <input type ="text" onChange ={(e) => props.onChangeStudentTo(e, props.id)} /> </div > );} export default student;
这里需要注意下,react的event和我们平时认为的JS的event不一样,相关文档见此: https://reactjs.org/docs/events.html
什么时候用 state?
需要动态改变组建内值的时候
需要使用组件的生命周期函数的时候
6. React中的样式
6.1 - 通过 import 导入样式
在Student.js同级目录创建Student.css
1 2 3 4 Student.css div { color :blue; }
在Student.js中使用该样式
6.2 - 直接在组件中定义样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Student .js import React from 'react' var myStyle = { color :"orange" , fontSize :"22px" } function student (props ) { return ( <div > <div style ={myStyle} > 大家好,我是学生:{props.name},班级:{props.class}</div > <input type ="text" onChange ={props.onChangeStudentTo.bind(this,props.id)} > </input > </div > ); } export default student;
7. 流程控制语句
7.1 - 条件判断语句
1 2 JSX语法 <div > {this.state.isShowGradeInfo?this.state.gradeInfo:""}</div >
1 2 3 4 5 6 7 8 9 10 11 12 13 render ( ) { let gradeInfo = null ; if (this .state .isShowGradeInfo ){ gradeInfo = this .state .gradeInfo ; } return ( <div className ="App" htmlFor ="html for for for demo" > ... <div > {gradeInfo}</div > ... </div > ); }
7.2 - 循环语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 render ( ) { ... var studentArray = []; for (let i=0 ;i<this .state .students .length ;i++){ studentArray.push (<Student id ={this.state.students[i].id} onChangeStudentTo ={this.changeStudentTo} name ={this.state.students[i].name} class ={this.state.students[i].class} /> ) } return ( <div className ="App" htmlFor ="html for for for demo" > ... {/* {studentArray} */} {this.state.students.map(student=>{ return <Student id ={student.id} onChangeStudentTo ={this.changeStudentTo} name ={student.name} class ={student.class} /> })} ... </div > ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 render ( ) { ... return ( <div className ="App" htmlFor ="html for for for demo" > ... { this.state.students.map(student=>{ return <Student id ={student.id} onChangeStudentTo ={this.changeStudentTo} name ={student.name} class ={student.class} /> }); } ... </div > ); }