类似于vue-cli的react架子
react官网
react中文官网
redux
React Router 文档
#
准备
git clone https://github.com/reactjs/react-router-tutorial.gitcd lessons/01-setting-upnpm inpm start
浏览器打开http://localhost:8080/
创建Demo.js
// Demo.jsimport React, { Component} from 'react'export default class Demo1 extends Component { constructor (props) { super(props) this.state = { msg: "demo1" } } render () { let {msg} = this.state return (
{ msg }
) }}
修改App.js
import React from 'react'
import Demo from './Demo';
export default React.createClass({
render() {
return (
)
}
})
现在可以点击进入react官网,选择快速开始~
#
开始
- hello world
这块的代码很简单,具体可以看项目的app.js入口文件。
重点是 ReactDOM.render可以绑定应用到dom
接下来正式开始学习
ReactDOM.render(
Hello, world!
, document.getElementById('your id'));
#
JSX
作用是react的视图
js的一种拓展语言,就是在js里面插入html标签。
vscode推荐插件:Auto Close Tag Babel JavaScript
以下的例子都可以用项目的demo1.js中尝试
注意点:
- jsx可以使用js表达式,必须写在{} 中
- "" 代表赋值,"{}" 这么写会被转译成字符串的值
- 标签中的class被改成了className,标签中的属性名全都要写成小驼峰命名
- 例子
const element =
Hello, world!
;const animal = { cat: '小宝', dog: '小贝',}// 使用render () { let {msg} = this.state return (
{ msg }
{animal.dog}
) }// 定义属性const imgSrc='xxx/asset/xxx.png'const h1 =
class
// 可以用 {} 进行赋值,但是用了{} 就别用""包裹了,否则为字符串 const img = // const img = error
vue中是用.vue文件直接把html css js一并囊括了,但是react没有单独的.文件 。所以jsx就相当于是react的视图部分了。
没有v-if v-for之类的语法,全是原生写法的js实现的,后面介绍。
#
组件 & props
#
vue组件 VS react 组件
- vue中声明使用组件
// 声明全局组件Vue.component('welcome',{ template: `
home
`, props: ['name']})// 使用
- react声明使用组件
// 一个函数组件function Welcome(props){ return
home
}// 类组件class Welcome extends React.Component { render() { return
Hello, {this.props.name}
; }}const component = ();
不用想了,类组件肯定是最常用的形式了。
可以看到声明的方式略有不同,但使用方式是一致的。
警告:
组件名称必须以大写字母开头。
例如,
表示一个组件,并且在使用该组件时你必须定义或引入它。组件必须由一个跟元素包裹,这点跟vue一样。
#
vue props VS react props
不要在组件内部改变props的值,都是由外面传进来的。
class Welcome extends React.Component { render() { return
Hello, {this.props.name}
}}function App() { return (
#
vue data VS React State
data是vue组件中内部的值,React内部的值都放在了state里,但是写法有很大区别 vue中使用props和data都省去了this,用的是{{}} react的props是通过构造函数传过来的,state也是定义在constructor中,使用{}调用
// vue
Vue.component('demo',{
template: `
data() {
return {
msg: '内部的值'
}
}
})
// react
class Demo extends React.Component{
constructor(props) {
super(props);
this.state = { // 在此初始化内部的值
msg: '内部的值'
}
}
render() {
return {
}
}
}
#
vue VS React 之生命周期
mounted = componentDidMount destroyed = componentWillUnmount 当然并不是完全相同,这里是为了方便快速记忆。 react基本会在componentDidMount中调用接口,vue则在created || mounted调用 destroyed 和 componentWillUnmount 这俩在SPA开发中基本不会使用
#
React setState
setState是react特有的改值方法。在vue中要改变data中的某个值,直接赋值即可this.msg='改变' 而react禁止直接更新数据 this.setState({msg: '改变'}); 并且数据的更新可能是异步的,这是因为react会将多个setState合并调用。所以如下的代码是不对的。
this.setState({ counter: this.state.num1 + this.props.num2,});
要改成函数调用形式
// Correct
this.setState((prevState, props) => ({
// prevState 代表还没更新之前的数据
counter: prevState.num1 + props.num2
}));
#
vue VS react 事件处理
vue中绑定事件语法为@事件 react和原生绑定dom基本一样,不过名字是驼峰命名法改写的
click
aClick // 然后在vue组件对象中声明事件{ methods: { click(params) { alert('111') }, aClick() { alert('aaa') }, }}// react// 要在构造函数中 bind(this),在外部声明函数class Demo extends React.Component{ constructor(props) { super(props); this.state = { msg: '内部的值' } this.click = this.click.bind(this);// this.alick = this.alick.bind(this); 这里不需要bind了 } click() { } aClick(params,e) { // 如果要处理默认事件,必须这么写 e.preventDefault(); } render() { return {
click // 不想使用 bind ,可使用箭头函数 this.aClick(params,e)}>click
} }}
e 是一个合成事件,React内部自动处理了跨浏览器的问题
使用箭头函数简化bind的方法,会在将这个回调函数作为一个属性值传入低阶组件的时候造成额外的渲染,所以为了性能还是使用bind比较好。
#
vue VS React 之条件渲染
就是通过if条件判断渲染不同的dom节点 vue可以使用v-show v-if react是直接写jsx判断
// vueVue.components('demo',{ template: `
a
b
`, data() { flag: false }})// react// 要在构造函数中 bind(this),在外部声明函数class Demo extends React.Component{ constructor(props) { super(props); this.state = { flag: false } } render() { return {
if(this.state.flag){
a
}else {
b
}
} }}
#
阻止组件渲染
通过判断该组件是否渲染,直接在render方法中判断return null 即可
demo:
class Warning extends React.Component{ constructor(props) { super(props); } render() { if(!this.props.warn) { return null } return (
Warning!
) }}class Page extends React.Component { constructor(props) { super(props); this.state = {showWarning: true} this.handleToggleClick = this.handleToggleClick.bind(this); } handleToggleClick() { this.setState(prevState => ({ showWarning: !prevState.showWarning })); } render() { return (
{this.state.showWarning ? 'Hide' : 'Show'}
); }}ReactDOM.render( , document.getElementById('root'));
#
vue VS React 之循环
vue使用v-for和 :key 进行循环数据渲染 react使用jsx 先假定有个数组 arrs=[1,2,3,4,5]
// vue
- {{v}}
- { arrs.map( (v,i) => { return
- {{v}} }) }
#
vue VS React 之表单元素
input、select这块两个框架处理的很不一样,主要是思想的不同。 vue是双向绑定,react是单向数据流。 不过实现起来倒是有点相似,都是绑定value,再绑定input等表单事件把值改变
#
受控组件
// vue
// 当然你懂得 v-model是语法糖
// 拆开来是这样
react 使用一个叫受控组件的形式实现数据的响应
// reactclass Demo extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); // 绑定input事件 } handleChange(event) { this.setState({value: event.target.value}); // 每次input都 setState value } render() { return (
- textarea
react中的textarea改成了value形式
// reactclass Demo extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); // 绑定Change事件 } handleChange(event) { this.setState({value: event.target.value}); // 每次Change都 setState value } render() { return (
- select
使用value绑定选中的值
// reactclass Demo extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); // 绑定Change事件 } handleChange(event) { this.setState({value: event.target.value}); // 每次Change都 setState value } render() { return (
GrapefruitLimeCoconutMango
); }}
总之就是改成了value,就叫受控组件了。
#
非受控组件
非受控组件其实就是ref
#
状态提升 传值
其实就是组件间传值的过程
提倡将所有需要共享的数据,提到这些组件离得最近的父组件中进行操作。
import React,{Component} from 'react'class Insert extends Component { // 被调用的组件 constructor(props) { super(props) this.handleChange = this.handleChange.bind(this) } handleChange(e) { // 4. 回调了上层组件的函数并传值 this.props.handleInner(e.target.value) } render() { const {msg} = this.props const html = (
{/* 2. 初始化赋值 */} {/* 3. 改变内部组件的值,触发onChange */}
) return html }}class Parent extends Component { // 上层组件 constructor(props) { super(props); this.state = { msg: '初始值' // 1. 初始化值 } this.handleValue = this.handleValue.bind(this) } handleValue(value) { // 6. 更新外部的值 this.setState({ msg:value }) } render() { return (
{this.state.msg}
{/* 5. 上层组件回调被触发 */}
); }}const Welcome = () => (
#
包含关系Slot
其实就是slot
使用 props.children ,放在slot需要出现的位置
class LiItme extends Component { constructor(props) { super(props) } render() { const html = (
li-itme ) return html }}class UlTemp extends Component { constructor(props) { super(props); } render() { return (
- {this.props.children}
使用的是children是一个默认值。
且slot只可以有一个
如果需要多个slot,可以自行定义名称,相当于命名slot
import React,{Component} from 'react'class Left extends Component { // 被调用的组件 constructor(props) { super(props) } render() { const html = ( 左青龙 ) return html }}class Right extends Component { constructor(props) { super(props) } render() { const html = ( 右白虎 ) return html }}class DivTemp extends Component { constructor(props) { super(props); } render() { return (
{this.props.left}
老牛在当中
{this.props.right}
); }}const Welcome = () => (
} right={ } />
)export default Welcome