安装node和create-react-app
node安装 略过
create-react-app
npm i -g create-react-app
cd xxx // 目录
npm start
这时候就生成了一个简单的react页面
发现问题:serviceWorker.js是啥
service worker是在后台运行的一个线程,可以用来处理离线缓存、消息推送、后台自动更新等任务。registerServiceWorker就是为react项目注册了一个service worker,用来做资源的缓存,这样你下次访问时,就可以更快的获取资源。而且因为资源被缓存,所以即使在离线的情况下也可以访问应用(此时使用的资源是之前缓存的资源)。注意,registerServiceWorker注册的service worker 只在生产环境中生效(process.env.NODE_ENV === ‘production’)
dependecies: 生产环境中需要的
devDependencies: 开发环境需要的
发现问题:哪些包应该放在dependecies中,哪些包应该放在devDependencies中
babel,webpack等放在dependecies中
react,vue等放在devDependencies
JSX
JSX即 js and xml,可以解析所有js语言和html标签,
解析器遇到< 当做xml来解析,遇到{}当做js来解析
React Dom使用camelCase来定义属性的名称,如className,onClick,以及在style中写的marginLeft等
<span style={{marginLeft:10+'px'}}>删除</span>
jsx可以防止xss攻击,React DOM在渲染所有输入内容前,默认会进行转义。
在编译时,babel会吧JSX转义成名为React.createElement()函数调用,这个函数会进行一些检查,防止编写错代码
这两种代码等效
// 写法1:
const element = (
<h1 className="test">
hello
</h1>
)
// 写法2:
const element = React.createElement(
'h1',
{className:'test'},
hello
)
写法:
// JSX写法
class App extends Component{
render(){
return{
<ul className="test">
<li>item1</li>
<li>item2</li>
</ul>
}
}
}
// 不用JSX的写法
var child1 = React.createElement('li',null,"item1")
var child2 = React.createElement('li',null,"item2")
var root = React.createElement('ul',{className:'my-list'}.child1,child2)
// index.js
import App from ‘./App’
这里的App是自定义组件,必须要以大写字母来开头。
Fragment
类似于vue中的template,不需要标签,但是react中一定要用div包裹。
使用Fragment需要引用
元素渲染
“根” DOM 节点,因为该节点内的所有内容都将由 React DOM 管理。
React 只会更新改变的dom部分,其他部分不更新
组件与Props
定义组件的方式: 函数组件和class组件
React元素可以是用户自定义的组件:
const element = <Welcome name="Sara" />;
数据绑定,事件绑定
增加数据在construstor中增加
数据绑定和事件绑定写在JSX中
mport React,{Component,Fragment} from 'react'
class Xiaojiejie extends Component{
// 这里的constructor是用来增加数据的
constructor(props){
super(props)
this.state={
inputValue: 'jsPang',
list: []
}
}
render(){
return (
<Fragment>
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)}/>
<button>增加服务</button>
</div>
<ul>
<li>头部按摩</li>
<li>精油推背</li>
</ul>
</Fragment>
)
}
inputChange(e){
console.log(e.target.value)
this.setState({
inputValue: e.target.value
})
}
}
export default Xiaojiejie
这时候,我们把数字绑定以及事件绑定做好了
下一步,
- 用循环的方式,把list队列中的事件渲染出来
- 通过事件改变list,在list中可以添加新的任务
react的循环怎么写
参考地址:react中的for循环
写法一(贴出部分代码)
constructor(props){
super(props)
this.state={
inputValue: '',
list: ['头部按摩','精油推背']
}
}
render(){
return (
<Fragment>
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button>增加服务</button>
</div>
<ul>
{
this.state.list.map((item, index) => {
return <li key={item+index}>{item}</li>
})
}
</ul>
</Fragment>
)
}
写法二:
render(){
return (
<Fragment>
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button>增加服务</button>
</div>
<ul>
{
this.insertStr()
}
</ul>
</Fragment>
)
}
insertStr(){
let str = this.state.list.map((item, index) => {
return <li key={item+index}>{item}</li>
})
console.log(str) // $$typeof: Symbol(react.element),key:精油推背1,props:{children:'精油推背'},ref:null,type:li
return str
}
写法三:
render(){
return (
<Fragment>
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button>增加服务</button>
</div>
<ul>
{
this.insertStr()
}
</ul>
</Fragment>
)
}
insertStr(){
let str = []
for(let i=0; i<this.state.list.length; i++) {
str.push(<li key={i}>{this.state.list[i]}</li>)
}
console.log(str) // $$typeof: Symbol(react.element),key:1,props:{children:'精油推背'},ref:null,type:li
return str
}
完成了循环渲染,下一步是添加,首先添加添加事件
1.
<button onClick={this.addService.bind(this)}>增加服务</button>
...省略好几行...
addService(e){
let myList = this.state.list
myList = [...this.state.list, this.state.inputValue]
this.setState({
list:myList
})
}
注意:上面事件的写法,先用一个myList列表把要修改的state中的list保存起来,然后先去操作myList,之后再用setState方法把list赋值进去。
后续优化:
1.每次添加完,都让input框的内容置空
2.添加成功后,让input自动focus
3.添加删除按钮
1.setState里面让inputValue为""就可以了
2.暂时不知道怎么解决
3.在jsx中写行内style样式的写法
<li key={item+index}>{item}<span style={{marginLeft:10+'px'}}>删除</span></li>
to-do基本完成:
render(){
return (
<Fragment>
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addService.bind(this)}>增加服务</button>
</div>
<ul>
{
this.state.list.map((item, index) => {
return <li key={item+index}>
{item}
<span className='del' onClick={this.remove.bind(this,index)}>删除</span>
</li>
})
}
</ul>
</Fragment>
)
}
inputChange(e){
this.setState({
inputValue:e.target.value
})
}
addService(){
let list = this.state.list
list = [...this.state.list, this.state.inputValue]
this.setState({
inputValue:'',
list
})
}
remove(e){
let list = this.state.list;
list.splice(e,1);
this.setState({
list
})
}
组件分离:
将to-do中的service(头部按摩,精油推背)分离出来
1.新增一个service.js组件
在service的render中获取接收的参数
// service.js
render() {
return (
<Fragment>
<span dangerouslySetInnerHTML={{__html:this.props.item}}></span>
<span className='del' onClick={this.props.remove}>删除</span>
</Fragment>
);
}
在xiaojiejie.js中引用
// xiaojiejie.js
import myService from './service'
//省略代码...
render(){
...省略代码
<ul>
{
this.state.list.map((item, index) => {
return <li key={item+index} >
<MyService remove={this.remove.bind(this,index)} item={item}></MyService>
{/**
* 这里是之前的代码
* <span dangerouslySetInnerHTML={{__html:item}}></span>
* <span className='del' onClick={this.remove.bind(this,index)}>删除</span>
*/}
</li>
})
}
</ul>
}
remove(e){
let list = this.state.list;
list.splice(e,1);
this.setState({
list
})
}
在vue中,删除是通过组件的$emit传回一个值给父元素,父元素来做删除,或是在组件中新增一个删除事件,然后删除。在react中,则是把父组件的事件传递给子组件,让子组件去调用,子组件往这个方法传参,在父组件中接收参数,来实现父子组件传递。
子组件向父组件传值
// 父组件
// 给子组件的属性deleteItem上绑定了自己的remove方法,这个方法有参数idx,用来接收子组件传递回来的参数
<MyService deleteItem={this.remove.bind(this)} index={index} key={item+index} item={item}></MyService>
...代码
remove(idx){
let list = this.state.list;
list.splice(idx,1);
this.setState({
list
})
}
// 子组件
render() {
return (
<Fragment>
<span dangerouslySetInnerHTML={{__html:this.props.item}}></span>
<span className='del' onClick={this.handleClick.bind(this)}>删除</span>
</Fragment>
);
}
handleClick(){
// 调用父组件传递过来的方法,并且把indexsuoyi
this.props.deleteItem(this.props.index)
}
几个注意点:
1.jsx的注释写法
<div>
{/**
* 写注释需要用{}包住,其他和js中一样
*/}
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addService.bind(this)}>增加服务</button>
</div>
2.如果想要实现类似v-html的效果,在input框中输入<h1>123</h1>
,让123放大加粗,那要用dangerouslySetInnerHTML
,让代码实现html
格式的输出
<ul>
{
this.state.list.map((item, index) => {
return <li key={item+index} >
<span dangerouslySetInnerHTML={{__html:item}}></span>
<span className='del' onClick={this.remove.bind(this,index)}>删除</span>
</li>
})
}
</ul>
label for
在jsx中,label for要写成 <label htmlFor="xx">
,避免和js中的for循环混淆
react插件
Simple React Snippets
快速引入:在vscode中输入imrc,就可以快速生成常用的import
输入cc,可以快速生成组件的基本代码