一、受控组件和非受控组件
React组件的数据渲染是否被调用 是通过 传递过来的props完全控制
控制则为受控组件,否则非受控组件。
二、数据渲染
1、条件渲染
{ flag ? "开启" : "关闭" }
2、列表渲染
渲染的元素必须用key属性做唯一标识
const people = [{
id: 1,
name: 'Leo',
age: 35
}, {
id: 2,
name: 'XiaoMing',
age: 16
}]
// 渲染列表
{
people.map(person => {
return (
<dl key={person.id}>
<dt>{person.name}</dt>
<dd>age: {person.age}</dd>
</dl>
)
})
}
使用
dangerouslySetHTML
属性,它允许我们动态设置innerHTML
<div dangerouslySetInnerHTML={{__html: this.state.content}} />
三、事件处理
1、React的事件并不是原生事件,而是合成事件。所以命名使用驼峰命名法,如onClick。
2、事件handle的写法
- 直接在render里写行内的箭头函数(不推荐)
- 在组件内使用箭头函数定义一个方法(推荐)
- 直接在组件内定义一个非箭头函数的方法,然后在render里直接使用
onClick={this.handleClick.bind(this)}
(不推荐) - 直接在组件内定义一个非箭头函数的方法,然后在constructor里bind(this)(推荐)
注意: 事件不能定义在函数式
3、event对象
React中的event对象并不是浏览器提供的,而是它自己内部所构建的。
它同样具有event.stopPropagation
、event.preventDefault
这种常用的方法
事件对象中的值很多都是null,但是可以正常使用
4、事件的参数传递
- 在render里调用方法的地方外面包一层箭头函数
- 在render里通过
this.handleEvent.bind(this, 参数)
这样的方式来传递 - 通过
event
传递 - 比较推荐的是做一个子组件, 在父组件中定义方法,通过
props
传递到子组件中,然后在子组件件通过this.props.method
来调用//处理用户输入 import React, { Component } from 'react' import ReactDOM from 'react-dom' class App extends Component { constructor() { super() this.state = { xing: '', ming: '' } } handleInputChange = (e) => { this.setState({ [e.target.name]: e.target.value }) } render () { const { xing, ming } = this.state return ( <div> <label> <span>姓:</span> <input type="text" name="xing" value={xing} onChange={this.handleInputChange} /> </label> <label> <span>名:</span> <input type="text" name="ming" value={ming} onChange={this.handleInputChange} /> </label> <p>欢迎您: {xing}{ming}</p> </div> ) } } ReactDOM.render( <App/>, document.getElementById('root') )
- ref绑定:
普通绑定
<input type="text" ref = "user"/>
函数形式
<input type="text" ref = { el => this.user = el }/>
四、组件通信
1、父子组件通信
无论父组件传递是props还是state,子组件都是通过props接收
2、子父组件通信
父组件传递方法给子组件,子组件调用父组件传递过来的方法
注意: 自己的状态自己更改
3、非父子组件通信
ref = ‘xxx’ this.refs.xxx
ref = { el => this.xxx = el } this.xxx 【 推荐 】
4、跨组件通信
- 创建上下文 React.createContext()
- 使用上下文包裹目标组件的父组件
<MoneyContext.Provider value = { money }>
<Father></Father>
</MoneyContext.Provider>
- 在目标组件中先定义一个静态属性 static contextType = MoneyContext
- 通过 this.context来使用数据
// counterContext.js
import React, { Component, createContext } from 'react'
const {
Provider,
Consumer: CountConsumer
} = createContext()
class CountProvider extends Component {
constructor () {
super()
this.state = {
count: 1
}
}
increaseCount = () => {
this.setState({
count: this.state.count + 1
})
}
decreaseCount = () => {
this.setState({
count: this.state.count - 1
})
}
render() {
return (
<Provider value={{
count: this.state.count,
increaseCount: this.increaseCount,
decreaseCount: this.decreaseCount
}}
>
{this.props.children}
</Provider>
)
}
}
export {
CountProvider,
CountConsumer
}
// 定义CountButton组件
const CountButton = (props) => {
return (
<CountConsumer>
// consumer的children必须是一个方法
{
({ increaseCount, decreaseCount }) => {
const { type } = props
const handleClick = type === 'increase' ? increaseCount : decreaseCount
const btnText = type === 'increase' ? '+' : '-'
return <button onClick={handleClick}>{btnText}</button>
}
}
</CountConsumer>
)
}
// 定义count组件,用于显示数量
const Count = (prop) => {
return (
<CountConsumer>
{
({ count }) => {
return <span>{count}</span>
}
}
</CountConsumer>
)
}
// 组合
class App extends Component {
render () {
return (
<CountProvider>
<CountButton type='decrease' />
<Count />
<CountButton type='increase' />
</CountProvider>
)
}
}
5、多组件状态共享
- Flux
- redux
- mobx 【 阿里 】