初始化及安装依赖
cmd
$ mkdir react-demos
$ cd react-demos
$ npm init --yes
$ npm install --save babel-standalone react react-dom
Hello World
<div id="app"></div>
<!-- <script src="node_modules/@babel/standalone/babel.js"></script> -->
<script src="node_modules/babel-standalone/babel.min.js"></script>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script type="text/babel">
ReactDOM.render(
<h1>hell react</h1>,
document.getElementById("app")
)
</script>
基本语法
const user = {
name:"小明",
age:18,
gender:0
}
const element = (
<div>
<h1>
{
/*
* 注释写法
*
*/
}
哎呦喂是 { user.name} 都 { user.age } 了是个 { user.gender == 0 ? "男" : "女" } 的,
</h1>
<div className="box">
<input type="text" defaultValue={user.name}/>
</div>
</div>
)
ReactDOM.render(
element,
document.getElementById("app")
)
列表渲染
const lis = [
<li key="1">苹果</li>,
<li key="2">梨子</li>,
<li key="3">香蕉</li>,
]
const todos = [
{
id: 1,
title: '吃饭'
},
{
id: 2,
title: 'sleep'
},
{
id: 3,
title: '大'
}
]
//循环遍历数组对象
const todlis = todos.map(timet => {
return <li key={ timet.id }>{ timet.title }</li>
})
const element = (
<div>
<ul>
{lis}
</ul>
<ul>
{ todlis }
</ul>
</div>
)
ReactDOM.render(
element,
document.getElementById("app")
)
事件绑定
function cc(){
alert("hell")
}
// 1. 使用驼峰命名
// 2. 必须绑定一个函数
// 3. 不能使用字符串的方式,一定要使用 {函数} 来绑定
const element = (
<div>
<button type="button" onClick={cc}>点击hell</button>
</div>
)
ReactDOM.render(
element,
document.getElementById("app")
)
函数组件 (无状态)
//组件名开头必须大写
//props 用来组件与组件之间传递参数
function AppHeader(props) {
return (
<div>
<h1>我是{ props.data }头部</h1>
</div>
)
}
const element = (
<div>
<AppHeader data="帅气的"/>
<AppHeader data="漂亮的"/>
</div>
)
ReactDOM.render(
element,
document.getElementById("app")
)
class 基本语法
const classF = class{
//constructor 就是类的构造函数
constructor(name,age){
this.name = name,
this.age = age
}
show() {
//
console.log(`hell ${this.name}`)
}
}
const newClsF = new classF('小明',18);
newClsF.abc="abc";
newClsF.show();
console.log(newClsF)
class 继承
const user = class{
constructor(name,age) {
this.name = name,
this.age = age
}
show() {
console.log(`你好 ${this.name}`)
}
}
// class 可以使用 extends 关键字实现对父类的继承
// 不仅可以继承属性,还可以继承父类的原型方法
// 这里继承的本质是使用的:原型式继承
// 注意:在子类中,如果没有写 constructor 则不需要调用 super
// 如果一旦写了 constructor ,就必须手动调用一下 super 父类构造函数,否则报错
class tec extends user {
constructor(name,age) {
// super 就父类构造函数
// 借用父类构造函数,把 name、age 初始化到 tec
super(name,age)
}
hidden(){
console.log(`我不好 ${this.name}`)
}
}
const su = new user("小明",18);
su.show();
const st = new tec("老王",38);
st.show();
st.hidden();
类方式组件(有状态)
- class 组件类,必须继承自 React.Component 才是一个组件类,否则就是一个普通的类
- 在组件类中,必须通过 render 渲染函数返回组件模板
- 接下来就可以在其它能访问到这个组件类的作用域中去使用这个组件了
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
ReactDOM.render(
<ShoppingList />,
document.getElementById("app")
)
// Example usage: <ShoppingList name="Mark" />
本质:
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);
组件传值 Props
- 父 传值
class App extends React.Component{
constructor(props) {
super(props)
this.state = {
data:["吃饭","睡觉","打代码"]
}
}
render() {
return (
<div>
<h1>添加列表小案例</h1
<List data1={this.state.data}/>
</div>
)
}
}
- 子 内部接收
class List extends React.Component{
constructor() {
super()
this.state = {
}
}
render() {
console.log(this.props)
return (
<ul>
{
this.props.data1.map( (itme,index) => <li key={ index }>{ itme }</li>)
}
</ul>
)
}
}
console.log(this.props)
打印子接收的props
子组件改变父组件数据
- 父定义方法子调用方法来处理
- 父
class App extends React.Component{
constructor(props) {
super(props)
this.state = {
data:["吃饭","睡觉","打代码"]
}
// 将this传递个方法
this.addData = this.addData.bind(this)
}
// 父定义方法
addData(NewData) {
let oldData = this.state.data;
oldData.unshift(NewData)
this.setState({
data:oldData
})
}
render() {
return (
<div>
<h1>添加列表小案例</h1> // 将方法传给子
<Add data2={this.state.data.length} addData={this.addData}/>
<List data1={this.state.data} />
</div>
)
}
}
组件 state
class MyComponent extends React.Component{
constructor(){
// 如果子类加入了 constructor 构造函数,则一定要手动调用父类的构造函数 super
super()
// React 组件需要通过手动为组件类添加 state 成员来初始化:ViewModel
// state 等价于 Vue 中的 data
// 接下来就可以在该组件管理的模板中通过 {} 来访问绑定数据了
this.state = {
meccuss:true
}
}
hTap() {
let isTrue = !this.state.meccuss
console.log(isTrue)
//更新数据
this.setState({
meccuss:isTrue
})
}
render() {
const isTrue = this.state.meccuss
return (
<h1 onClick={this.hTap.bind(this)}>{ isTrue ? "可以的" : "不可以"}</h1>
)
}
}
ReactDOM.render(<MyComponent /> , document.getElementById("app"))
- 子
class Add extends React.Component{
constructor() {
super()
this.state = {
}
this.add = this.add.bind(this)
}
add(){
let data = this.MyInput.value
if (!data) {
alert("请输入内容!")
return
}
console.log(this.props)
//子通过props 调用 实现数据更新
this.props.addData(data)
this.MyInput.value = ""
}
render() {
const data = this.props.data2;
return (
<div>
<input type="text" ref={ input => this.MyInput = input}/>
<button onClick={this.add}>添加 #{ data + 1 }</button>
</div>
)
}
}
组件ref
与事件 event
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
console.log("啊啊啊啊")
this.refs.myTextInput.focus();
this.refs.mySpan.focus();
console.log(this.refs) //查看全部ref
console.log(this.refs.mySpan.id) //通过ref获取到了id
}
render(){
return (
<div>
{ /*//定义名字 使用通过this.refs.myTextInpu*/ }
<input type="text" ref="myTextInput" />
<span id="a1" ref="mySpan">我是span</span>
<input type="button" value="输入内容" onClick={this.handleClick} />
</div>
)
}
}
export default App;
class MyComponent extends React.Component{
constructor() {
super()
this.state = {
}
this.showData1 = this.showData1.bind(this);
this.dataBlur = this.dataBlur.bind(this);
}
showData1() {
const data = this.refs.abc1;
const refInput = this.refInput;
// alert(data.value)
alert(refInput.value)
}
dataBlur(e) {
alert(e.target.value)
}
render() {
return (
<div>
{ /* 传统的ref使用 */}
<input type="text" ref="abc1"/>
{ /*
react推荐使用 (相当于 function(input) { return this.refInput = input}
input为dom input这个元素
获取就通过 this.refInput来获取
*/}
<input type="text" ref={ (input) => this.refInput = input }/>
<button type="button" onClick={this.showData1}>点击</button>
<input type="text" onBlur={this.dataBlur}/>
</div>
)
} }
ReactDOM.render(<MyComponent />,document.getElementById("app"))
类组件 绑定事件 this传值 数据驱动视图
事件绑定
- 第一种
- this指向window
- 默认接受一个
event
事件源对象 - 不支持传参
<button onClick= { this.tapClick }>01+1</button>
- 第二种 (推荐)
this
指向组件实列 -> recat- 默认接受一个
event
事件源对象 - 可以传多个参数
- 参数序列是反的 event为最后一个参数
<button onClick= { this.tapClick.bind(this,123,456) }>+1</button>
- 第三种
- 自动 绑定 this
- 手动传参
- 参数顺序自定义
event
要手动传递
<button onClick={ (e) => { this.tapClick(e,123,456) } }>03</button>
class HeaderApp extends React.Component {
constructor () {
// 如果子类加入了 constructor 构造函数,则一定要手动调用父类的构造函数 super
super()
// React 组件需要通过手动为组件类添加 state 成员来初始化:ViewModel
// state 等价于 Vue 中的 data
// 接下来就可以在该组件管理的模板中通过 {} 来访问绑定数据了
this.state = {
title:"巴拉巴拉巴拉"
}
}
render(){
return (
<div>
<ul>
<li>{ this.state.title }</li>
<li>{ this.state.title }</li>
<li>{ this.state.title }</li>
</ul>
{ /* 最简单的绑定事件 处理简单的逻辑 推荐使用第二种*/ }
<button onClick= { this.tapClick }>01+1</button>
{/* //事件绑定 */} {/* .bind(this) 将react的this传给方法 也可以传值*/}
{ /* 这种传值方法方法接受的参数时候是反的 event为最后一个参数 默认接受event*/ }
<button onClick= { this.tapClick.bind(this,123,456) }>+1</button>
{ /* 这种传值方法方法接受的时候参数不是反的 但比较繁琐 推荐使用上种 */ }
<button onClick={ (e) => { this.tapClick(e,123,456) } }>03</button>
</div>
)
}
//方法
tapClick(e) {
let i = 2
console.log(this.state.title)
i++
//修改state中的值 实现数据驱动视图
this.setState({
title:`巴拉巴拉巴拉 ${ i }`
})
}
//使用第二种方法参数应该反写
tapClick2(num2,num1,e) {
console.log(this.state.title)
console.log(e.target)
console.log(num1)
console.log(num2)
}
}
- tapClick2 输出
设置组件参数的默认值,必要性及指定参数类型
-
使用 PropTypes 进行类型检查
注意:
React.PropTypes
自 React v15.5 起已弃用。请使用prop-types
库代替。
function Afun (props) {
return (
<ul>
<li>{ props.name }</li>
<li>{ props.age }</li>
<li>{ props.sex }</li>
</ul>
)
}
{ /* 指定属性的类型及必要性 */}
{ /* name类型必须为字符串 不能为空 */}
{ /* age必须为数字类型 */}
Afun.propTypes = {
name:PropTypes.string.isRequired,
age:PropTypes.number
}
{ /* 指定属性的默认值 */}
Afun.defaultProps = {
age:18,
sex:"男"
}
var data = {
name:"小明"
}
{ /* ...语法 “打包 与 解码”
如果data是一个集合(对象或数组) 那就解码 拆分成(data.name,data.age)传入
反之打包成一个集合(对象或数组)
*/}
ReactDOM.render(<Afun {...data} />,document.getElementById("app"))
列表渲染
const datas = [
{id:1,name:"小明",age:18,gender:0},
{id:2,name:"小红",age:17,gender:1},
{id:3,name:"小路",age:24,gender:0},
{id:4,name:"小乔",age:18,gender:1},
]
class Element extends React.Component {
constructor(){
super();
{/* 相当于vue 中的data*/}
this.state = {
datas
}
}
render() {
return (
<div>
<table border="1" cellspacing="1" cellpadding="1">
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
{/* 接收返回的数组 */}
{ this.showData() }
</table>
</div>
)
}
// 循环渲染数据
// 调用map方法 返回一个数组
showData() {
return this.state.datas.map(item => {
return (
<tr key={ item.id }>
<td>{ item.name }</td>
<td>{ item.age }</td>
<td>{ item.gender == 0 ? "男" : "女" }</td>
</tr>
)
})
}
}
ReactDOM.render(
<Element />,
document.getElementById("app")
)
条件渲染
参考文档:https://reactjs.org/docs/conditional-rendering.html
示例1:
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
示例2:
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
示例3(行内判断):
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{/* 如果满足条件 就显示h2 内容*/}
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
示例4(if-else):
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
示例5(阻止组件渲染):
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
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 (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
数据的更新
class ShoppingList extends React.Component {
render() {
return (
<div placeholder="添加新内容" autoFocus onKeyDown={this.keyDom.bind(this)} />
</div>
);
}
keyDom(e) {
const key = e.keyCode;
console.log(key)
const text = e.target.value
const idd = this.state.data[this.state.data.length -1].id;
if (key == 13 && text != ""){
const text = e.target.value
// 先更新数据 !!!
this.state.data.push({
id:idd + 1,
title:text,
completed:false
})
// 后通知 React 更新数据 !!!
this.setState({
data:this.state.data
})
}
}
}
ReactDOM.render(
<ShoppingList />,
document.getElementById("app")
)