2、React模块与组件
模块与组件的理解
- 模块
- 向外提供特定功能的js 程序, 一般就是一个js 文件
- 复用js, 简化js 的编写, 提高js 运行效率
- 组件
- 用来实现特定(局部)功能效果的代码集合(html/css/js)
- 复用编码, 简化项目编码, 提高运行效率
组件的基本使用
创建组件有两种方式
工厂函数组件
简单组件,通过函数返回值即可。函数名就是组件(标签)名。
function MyComponent() { return <h2>工厂函数组件(简单组件)</h2> } ReactDOM.render(<MyComponent />, document.getElementById('test'))ES6类组件
复杂组件,通过ES6类中的render方法。
class MyComponent2 extends React.Component { render() { return <h2>ES6类组件(复杂组件)</h2> } } ReactDOM.render(<MyComponent2 />, document.getElementById('test2'))
组件三大属性
state
state用于记录属性,其声明在constructor中,值是一个对象。(简单组件中没有状态)
constructor(props) {
// 固定写法
super(props)
// 设置属性
this.state = {
isLikeMe: false
}
}在render中可以通过this.state.xxx获取相关属性的值。此时的this指向当前对象。
render() {
// 读取状态
const { isLikeMe } = this.state
return <h2 onClick={this.handleClick}>{isLikeMe ? '你喜欢我' : '我喜欢你'}</h2>
}为h2标签绑定事件只需要在类中新增方法即可,但其默认this并不是指向当前对象,而是undefiend因此,需要在constructor将其指向当前对象。
class Like extends React.Component {
// 接受一个参数
constructor(props) {
// 固定写法
super(props)
// 设置属性
this.state = {
isLikeMe: false
}
// 将新增的方法中的this强制绑定为组件对象
this.handleClick = this.handleClick.bind(this)
}
// 新添加方法:内部的this默认不是组件对象,而是undefined
handleClick() {
// 得到状态
const isLikeMe = !this.state.isLikeMe
// 更新状态
this.setState({ isLikeMe })
}
render() {
// 读取状态
const { isLikeMe } = this.state
return <h2 onClick={this.handleClick}>{isLikeMe ? '你喜欢我' : '我喜欢你'}</h2>
}
}props
基本用法
function Person(props) {
return (
<ul>
<li>姓名:{props.name}</li>
<li>年龄:{props.age}</li>
<li>性别:{props.sex}</li>
</ul>
)
}
const p1 = {
name: 'Tom',
age: 18,
sex: '女'
}
ReactDOM.render(<Person name={p1.name} age={p1.age} sex={p1.sex} />, document.getElementById('test'))属性传入时也可以使用扩展运算符
ReactDOM.render(<Person {...p1} />, document.getElementById('test'))通过ES6类的继承实现语法
class Test extends React.Component {
// 接受一个参数
constructor(props) {
// 固定写法
super(props)
}
render() {
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>年龄:{this.props.age}</li>
<li>性别:{this.props.sex}</li>
</ul>
)
}
}默认值
Person.defaultProps = { sex: '男', age: 18 }设置属性的类型
需要引入
react-type文件// 指定属性类型和必要性 Person.propTypes = { name: PropTypes.string.isRequired, age: PropTypes.number }
refs和事件处理
为元素绑定
ref<input type="text" ref='content' />事件中通过
this.refs.content即可拿到当前DOM元素showInput() { const input = this.refs.content alert(input.value) }
官方推荐的写法并不是使用字符串,而是使用一个函数,将其挂载到React对象中。
<input type="text" ref={input => this.input = input}此时通过this.input.value即可拿到值。
组件组合使用
DEMO涉及到三个组件与组件之间的传值。其原则如下
- 都需要使用到的数据则放在父组件中
- 状态定义在哪个组件,则哪个组件修改状态
- 父组件将修改状态的函数作为
props属性传递给子组件
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
todos: ['吃饭', '睡觉', '打代码']
}
// 绑定this
this.addItem = this.addItem.bind(this)
}
// 添加值的具体方法
addItem(val) {
// 将值放到数组最前方
this.state.todos.unshift(val)
// 设置状态
this.setState(this.state)
}
render() {
const {todos} = this.state
// 将addItem方法作为属性传入到子组件
return (
<div>
<h1>Simple TODO List</h1>
<Add count={todos.length} addItem={this.addItem}/>
<List todos={todos}/>
</div>
)
}
}
class Add extends React.Component {
constructor(props) {
super(props);
this.addItem = this.addItem.bind(this)
}
addItem() {
// 获取input的值
const todo = this.todoInput.value.trim()
if (!todo) return
// 调用父组件传来的方法
this.props.addItem(todo)
this.todoInput.value = ''
}
render() {
// 为input标签挂载到当前对象的属性
return (
<div>
<input type="text" ref={input => this.todoInput = input}/>
<button onClick={this.addItem}>add #{this.props.count + 1}</button>
</div>
)
}
}
Add.propsTypes = {
count: PropTypes.number.isRequired,
addItem: PropTypes.func
}List组件渲染
class List extends React.Component {
render() {
return (
<ul>
{
this.props.todos.map((todo, index) => <li key={index}>{todo}</li>)
}
</ul>
)
}
}
List.propsTypes = {
todos: PropTypes.array.isRequired
}表单
收集表单数组有两种方式
受控组件
表单项输入数据能自动收集成状态
class LoginForm extends React.Component { constructor(props) { super(props) this.state = { pwd: '' } this.handleSubmit = this.handleSubmit.bind(this) this.handleChange = this.handleChange.bind(this) } handleSubmit(e) { const { pwd } = this.state e.preventDefault() } handleChange(e) { const pwd = e.target.value this.setState({ pwd }) } render() { return ( <form action='/test' onSubmit={this.handleSubmit}> 密码:<input type="password" value={this.state.pwd} onChange={this.handleChange} /> <input type="submit" value="登录" /> </form> ) } }非受控组件
需要时才手动读取表单输入框中的数据
class LoginForm extends React.Component { constructor(props) { super(props) this.handleSubmit = this.handleSubmit.bind(this) } handleSubmit(e) { const name = this.NameInput.value e.preventDefault() } render() { return ( <form action='/test' onSubmit={this.handleSubmit}> 用户名:<input type="text" ref={input => this.NameInput = input} /> <input type="submit" value="登录" /> </form> ) } }
生命周期
class Life extends React.Component {
constructor(props) {
super(props)
// 初始化状态
this.state = {
opactity: 1
}
this.distroy = this.distroy.bind(this)
}
// 挂载后的生命周期
componentDidMount() {
// 启动循环定时器
this.intervalId = setInterval(() => {
let { opactity } = this.state
opactity -= 0.1
if (opactity <= 0) {
opactity = 1
}
this.setState({ opactity })
}, 100)
}
distroy() {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
// 销毁时的生命周期
componentWillUnmount() {
clearInterval(this.intervalId)
}
render() {
const { opactity } = this.state
return (
<div>
<h2 style={{ opacity: opactity }}>{this.props.msg}</h2>
<button onClick={this.distroy}>不活了</button>
</div>
)
}
}组件的三个生命周期状态
Mount插入真实DOMUpdate被重新渲染Unmount被移出真实DOM
生命周期流程
重要的钩子
render()初始化渲染或更新渲染调用
componentDidMount()开启监听, 发送ajax 请求
componentWillUnmount()做一些收尾工作, 如: 清理定时器
componentWillReceiveProps()后面需要时讲
虚拟DOM和DOM diff算法
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 小康博客!
评论
TwikooDisqusjs
















