什么是 React ?
- React是一个声明式的,高效的,并且灵活的用于构建用户界面的 JavaScript 库
create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境。
create-react-app 自动创建的项目是基于 Webpack + ES6 。
执行以下命令创建项目:
-- 安装create-react-app脚手架
npm install -g create-react-app
-- 创建项目 my-app
create-react-app my-app
-- 进入到项目目录
cd testdemo
-- 运行项目
npm start
浏览器打开http://localhost:3000/,出现以下画面即为运行成功
class ShoppingList extends React.Componnet {
// 虚拟DOM
render() {
return (
<div className="shopping-list">
<h1>Shoping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatApp</li>
<li>Oculus</li>
</ul>
</div>
)
}
}
在这里,ShoppingList是一个 React组件类,或 React组件类型。组件接受参数,称为属性 props, 并通过 render方法返回一个现实的视图层次结构。
render 方法返回要渲染的内容描述,然后React接受该描述并将其渲染到屏幕上
注意:
由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。
实例中的 p 元素添加了自定义属性 data-myattribute,添加自定义属性需要使用 data- 前缀。
ReactDOM.render(
<div>
<p data-myattribute="somevalue">自定义属性</p>
</div>
,
document.getElementById('example')
);
React 推荐使用内联样式。
我们可以使用 camelCase 语法来设置内联样式. React 会在指定元素数字后自动添加 px 。以下实例演示了为 h1 元素添加 myStyle 内联样式:
var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style={myStyle}>菜鸟教程</h1>,
document.getElementById('example')
);
JSX 允许在模板中插入数组,数组会自动展开所有元素:
var arr = [
<h1>菜鸟教程</h1>,
<h2>学的不仅是技术,更是梦想!</h2>,
];
ReactDOM.render(
<div>{ arr }</div>,
document.getElementById('example')
);
componentWillMount:在渲染前调用,在客户端也在服务端。
componentDidMount ::在第一次渲染后调用,只在客户端。
componentWillReceiveProps:在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate:返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
componentWillUpdate:在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
componentDidUpdate:在组件完成更新后立即调用。在初始化时不会被调用。
componentWillUnmount:在组件从 DOM 中移除之前立刻被调用。
react生命周期函数详细
在 React 中不同的是你不能使用return false 的方式阻止默认行为, 你必须明确使用 preventDefault。
在 React 的写法为:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('链接被点击');
}
return (
<a href="#" onClick={handleClick}>
点我
</a>
);
}
react中,类的方法默认是不会绑定 this 的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined。
export default class Test extends Component {
constructor(props) {
super(props)
// 该处是为了绑定当前实例对象
this.testClick3 = this.testClick3.bind(this)
}
// 没有做任何绑定
testClick() {
console.log(this) // 打印 undefined
}
// 箭头函数
testClick2 = () => {
console.log(this) // 打印 当前实例对象
}
// 通过 constructor 中的 bind 绑定 this
testClick3() {
console.log(this) // 打印 当前实例对象
}
testClick4() {
console.log(this) // 打印 当前实例对象
}
render() {
return (
<>
<button onClick={this.testClick}>click1</button>
<button onClick={this.testClick2}>click2</button>
<button onClick={this.testClick3}>click3</button>
{/* 箭头函数 => 打印 当前实例对象 */}
<button onClick={() => this.testClick3()}>click4</button>
</>
)
}
}
通过 bind:
通过 箭头函数:
export default class Test extends Component {
constructor() {
super()
this.state = { name: 'Hello world!' }
}
// e: 打印事件对象 | name: Hello world!
testClick(name, e) {
console.log(e)
console.log(name)
}
render() {
return (
<>
{/* 使用bind传参,第一个参数是 事件对象, 第二个才是 方法所需参数 */}
<button onClick={this.testClick.bind(this, this.state.name)}>
click1
</button>
{/* 使用箭头函数传参,(e) 是事件对象,不传入的话,方法打印出来的 e 是 undefined */}
<button onClick={(e) => this.testClick(this.state.name, e)}>
click2
</button>
</>
)
}
}
Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性
(1)React.createContext:创建一个上下文的容器(组件), defaultValue可以设置共享的默认数据
const {Provider, Consumer} = React.createContext(defaultValue);
(2)Provider(生产者): 和他的名字一样。用于生产共享数据的地方。生产什么呢? 那就看value定义的是什么了。value:放置共享的数据。
<Provider value={/*共享的数据*/}>
/*里面可以渲染对应的内容*/
</Provider>
(3)Consumer(消费者):这个可以理解为消费者。 他是专门消费供应商( Provider)产生数据。Consumer需要嵌套在生产者下面。才能通过回调的方式拿到共享的数据源。当然也可以单独使用,那就只能消费到上文提到的defaultValue
<Consumer>
{value => /*根据上下文 进行渲染相应内容*/}
</Consumer>
setState(object nextState[, function callback])
参数说明
合并nextState和当前state,并重新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。
关于setState
不能在组件内部通过this.state修改状态,因为该状态会在调用setState()后被替换。
setState()并不会立即改变this.state,而是创建一个即将处理的state。setState()并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。
setState()总是会触发一次组件重绘,除非在shouldComponentUpdate()中实现了一些条件渲染逻辑。
replaceState(object nextState[, function callback])
**replaceState()方法与setState()**类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。
setProps(object nextProps[, function callback])
props相当于组件的数据流,它总是会从父组件向下传递至所有的子组件中。当和一个外部的JavaScript应用集成时,我们可能会需要向组件传递数据或通知React.render()组件需要重新渲染,可以使用setProps()。
更新组件,我可以在节点上再次调用React.render(),也可以通过**setProps()**方法改变组件属性,触发组件重新渲染。
replaceProps(object nextProps[, function callback])
forceUpdate([function callback])
参数说明
forceUpdate()方法会使组件调用自身的render()方法重新渲染组件,组件的子组件也会调用自己的render()。但是,组件重新渲染时,依然会读取this.props和this.state,如果状态没有改变,那么React只会更新DOM。
forceUpdate()方法适用于this.props和this.state之外的组件重绘(如:修改了this.state后),通过该方法通知React需要调用render()
一般来说,应该尽量避免使用forceUpdate(),而仅从this.props和this.state中读取状态并由React触发render()调用。
DOMElement findDOMNode()
如果组件已经挂载到DOM中,该方法返回对应的本地浏览器 DOM 元素。当render返回null 或 false时,this.findDOMNode()也会返回null。从DOM 中读取值的时候,该方法很有用,如:获取表单字段的值和做一些 DOM 操作。
bool isMounted()
isMounted()方法用于判断组件是否已挂载到DOM中。可以使用该方法保证了setState()和forceUpdate()在异步场景下的调用不会出错。
以上参考:https://www.runoob.com/react/react-component-api.html
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
export default class Test extends Component {
// constructor用于给state绑定实例
constructor(props) {
super(props)
// 设置state
this.state = {
msg: 'test msg',
msg2: 'setState msg',
}
}
// 上下两段都可用于设置state,但不能一起使用
// state = {
// msg2: 'test2 msg',
// }
render() {
return (
<>
{/* 获取state */}
{this.state.msg}
<button
onClick={() => {
this.state.msg = 'new test msg'
// 当改变了state时,不会主动更新,需要调用this.setState()来让页面渲染,重新加载render()
// this.setState()会更新当前页面所有的state,可以不用像msg2一样重复设置
this.setState({
msg2: 'setState msg',
})
}}
>
click
</button>
{/* {this.state.msg2} */}
</>
)
}
}
export default class Test extends Component {
constructor() {
super()
this.state = {
id: '1',
name: '小明',
sex: '男',
tableList: {
age: '22',
height: '180cm',
},
}
}
// 处理多个输入
// input 中的 name属性 要跟 state 的键对应
// 处理多个input
handleInputChange(e) {
const target = e.target
let name = target.name
this.setState({
[name]: target.value,
})
}
// 处理表单中的input值
_handleInputChange(e) {
const target = e.target
let name = target.name
let value = target.value
const tableList = this.state.tableList
tableList[name] = value
this.setState({
tableList,
})
}
render() {
return (
<>
{this.state.id}
<br />
{this.state.name}
<br />
{this.state.sex}
<br />
{this.state.tableList.age}
<br />
{this.state.tableList.height}
<form>
id:
<input
name="id"
value={this.state.id}
onChange={(e) => this.handleInputChange(e)}
/>
<br />
name:
<input
name="name"
value={this.state.name}
onChange={(e) => this.handleInputChange(e)}
/>
<br />
sex:
<input
name="sex"
value={this.state.sex}
onChange={(e) => this.handleInputChange(e)}
/>
<br />
age:
<input
name="age"
value={this.state.tableList.age}
onChange={(e) => this._handleInputChange(e)}
/>
<br />
height:
<input
name="height"
value={this.state.tableList.height}
onChange={(e) => this._handleInputChange(e)}
/>
</form>
</>
)
}
}
以上处理参考:https://www.cnblogs.com/xfswy/p/14980918.html
// class组件
export default class Test extends Component {
render() {
return (
<>
<button onClick={(e) => { console.log(e) }}>Test1 click</button>
{/* 展开Test2,并传递子节点 */
}
<Test2>
<h1>展开hello world</h1>
</Test2>
</>
)
}
}
// 函数式组件
// 该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)
// 对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。
const Test2 = (props) => {
function welcome(e) {
console.log(e)
console.log('hello world')
}
return (
<div>
<button onClick={(e) => welcome(e)}>Test2 click</button>
{/* 获取传递来的子节点 */}
{props.children}
</div>
)
}
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
// 函数式组件
// 这里是通过传参获取props,所以不需要使用this
const Test2 = (props) => <div>{props.msg2}</div>
// ES6 class关键字 定义
class Test3 extends Component {
render() {
// 这里是通过this访问当前实例获取props
return <div>{this.props.msg3}</div>
}
}
class Test4 extends Component {
// 通过静态属性 defaultProps 给props设置默认值
static defaultProps = {
msg4: 'default msg4',
}
render() {
return <div>{this.props.msg4}</div>
}
}
// 下方代码等价于上面Test4中的 static defaultProps
Test4.defaultProps = {
msg4: 'new default msg4',
}
export default class Test extends Component {
render() {
return (
<>
<Test2 msg2="test msg2" />
<Test3 msg3="test msg3" />
<Test4 />
</>
)
}
}
涉及以下知识点的使用
- state:状态保持以及更新
- 函数、事件处理
- 列表循环
- 条件渲染
写的很乱,看看就行
组件 home.js
import React, { Component } from 'react'
import './Home.css'
class Home extends Component {
constructor(props) {
super(props)
this.state = {
// 原始数据
tableList: [
{
id: '031',
name: '小明',
sex: '男',
age: '12',
height: '180',
weight: '79',
birthday: '1922-10-20',
},
{.............}
],
// 是否显示详细数据界面
isShowDetailed: false,
// 是否显示修改数据界面
isShowEdit: false,
// 详细数据表
detailedItem: {},
// 当前修改数据的key值
editKey: null,
// 修改数据界面模板以及存储当前需修改的数据
editItem: {
id: '1',
name: '1',
sex: '',
age: '',
height: '',
weight: '',
birthday: '',
},
}
// 为函数绑定当前对象,让函数可以获取到this
this.changeData = this.changeData.bind(this)
}
// 显示详细数据
showData = (data) => {
this.setState({
isShowDetailed: true,
detailedItem: data,
})
}
// 隐藏详细数据
hideData = () => {
this.setState({
isShowDetailed: !this.state.isShowDetailed,
})
}
// 显示修改数据
showEdit = (key) => {
this.setState(
{
isShowEdit: true,
editItem: this.state.tableList[key],
editKey: key,
},
() => {
let inputs = document
.getElementById('editId')
.getElementsByTagName('input')
for (let i = 0; i < inputs.length; i++) {
let key = Object.keys(this.state.editItem)
inputs[i].value = this.state.editItem[key[i]]
}
}
)
}
// 隐藏修改数据
hideEdit = () => {
this.setState({
isShowEdit: !this.state.isShowEdit,
})
}
// 修改数据
changeData() {
let data = this.state.tableList
data[this.state.editKey] = {
id: document.getElementById('id').value,
name: document.getElementById('name').value,
sex: document.getElementById('sex').value,
age: document.getElementById('age').value,
height: document.getElementById('height').value,
weight: document.getElementById('weight').value,
birthday: document.getElementById('birthday').value,
}
this.setState({
editItem: this.state.tableList[this.state.editKey],
isShowEdit: !this.state.isShowEdit,
isShowDetailed: !this.state.isShowDetailed,
})
}
// 删除数据
deleteData(key) {
this.state.tableList.splice(key, 1)
this.setState({
isShowDetailed: false,
isShowEdit: false,
})
}
// 虚拟DOM
render() {
return (
<div className="home">
<h1>调查</h1>
<table>
<tbody>
<tr>
<th></th>
<th>id</th>
<th>名称</th>
<th>性别</th>
<th>年龄</th>
<th>操作</th>
</tr>
{this.state.tableList.map((item, key) => {
return (
<tr key={item.id}>
<td>{key + 1}</td>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.sex}</td>
<td>{item.age}</td>
<td>
<button
className="info"
onClick={this.showData.bind(this, item)}
>
详细数据
</button>
<button
className="warning"
onClick={this.showEdit.bind(this, key)}
>
编辑
</button>
<button
className="danger"
onClick={this.deleteData.bind(this, key)}
>
删除
</button>
</td>
</tr>
)
})}
</tbody>
</table>
<div
className="detailed"
style={{ display: this.state.isShowDetailed ? 'block' : 'none' }}
>
<span>详细数据:</span>
<table>
<tbody>
<tr>
<th>id</th>
<th>名称</th>
<th>性别</th>
<th>年龄</th>
<th>身高(cm)</th>
<th>体重(kg)</th>
<th>生日</th>
<th>操作</th>
</tr>
<tr>
{Object.keys(this.state.detailedItem).map((obj, idx) => {
return <td key={idx}>{this.state.detailedItem[obj]}</td>
})}
<td>
<button
className="danger"
onClick={this.hideData}
title="关闭表单"
>
X
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div
className="edit"
id="editId"
style={{ display: this.state.isShowEdit ? 'block' : 'none' }}
>
<span>编辑数据:</span>
<table>
<tbody>
<tr>
<th>id</th>
<th>名称</th>
<th>性别</th>
<th>年龄</th>
<th>身高(cm)</th>
<th>体重(kg)</th>
<th>生日</th>
<th>操作</th>
</tr>
<tr>
{Object.keys(this.state.editItem).map((obj, idx) => {
return (
<td key={idx}>
<input id={obj} />
</td>
)
})}
<td>
<button className="smbit" onClick={this.changeData}>
确认
</button>
<button
className="danger"
onClick={this.hideEdit}
title="关闭表单"
>
X
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
)
}
}
export default Home
以上为个人笔记,不代表绝对正确,有错误还请帮忙指正