JSX 和虚拟 DOM 的关系
JSX 是一种语法,是一套独立的标准,由 React 引入,但不是 React 独有的,写法上类似 html ,但是有
- JS 变量和表达式
- if...else
- 循环
- style 和 className
- 事件
无法直接在浏览器运行,在 React 中需要通过函数( React.createElement )解析成虚拟 DOM...
虚拟 DOM 是 JS 对象, 这个对象有 JSX 的层次结构,用来模拟真实的 DOM ,这个对象拥有一些重要属性,并且更新 UI 主要就是通过对比(DIFF)旧的虚拟 DOM 树 和新的虚拟 DOM 树的区别完成的。
更为详细的介绍参考 手写一个 React
虚拟 DOM的历史由来,看这里
如何理解组件化
页面比较复杂时,拆分成一个个组件再去实现,就比较简单了
组件的封装,由三部分构成
- 视图
- 数据
- 逻辑(数据驱动视图变化)
class Todo extends Component {
constructor(props) {
this.state = {
list: []
}
}
render() {
return (
<div>
<Input addTitle = { this.addTitle.bind(this) }/>
<List data = { this.state.list }/>
</div>
)
}
addTitle(title) {
const currentList = this.state.list
this.setState({
list: currentList.concat(title)
})
}
}
组件的复用: 可以传递不同的数据
import Input from './input'
import List from './list'
class Todo extends Component {
constructor(props) {
super(props)
this.state = {
list: []
}
}
render() {
return (
<div> {/* 组件的复用 */}
<Input addTitle = { this.addTitle.bind(this) }/>
<List data = { this.state.list }/>
<List data = { this.state.list }/>
<List data = { this.state.list }/>
</div>
)
}
}
//子组件
class List extends Component {
render() {
const list = this.props.data {/* 通过props拿到父组件的数据 */}
return (
<ul>
{
list.map((item, index) => {
return <li key = {index}>{item}</li>
})
}
</ul>
)
}
}
什么是受控组件
<FInput value={x} onChange={fn}/> 受控组件
<FInput defaultValue={x} ref={input}/> 非受控组件
受控组件的状态由开发者维护,非受控组件的状态由组件自身维护(不受开发者控制)
什么是高阶组件
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
举个
React-Redux 里connect 就是一个高阶组件,比如connect(mapState)(MyComponent)
接受组件 MyComponent,返回一个具有状态的新 MyComponent 组件。
组件间通信
父给子传递:通过 props 传递(数据或方法),用 this.props.xxx 来接收
//父组件
<div>
<TodoItem content={item}/>
</div>
//子组件 TodoItem
<div>
{this.props.content}
</div>
子给父传递:子组件绑定事件,调用父组件中的方法,去修改父组件中的数据
//子组件
<div onclick={this.handleClick.bind(this)}>
{this.props.content}
</div>
handleClick() {
//调用父组件中的 yyy()
this.props.xxx()
}
//父组件
<div>
<TodoItem xxx={this.yyy.bind(this)}/> //把方法传递给子组件
</div>
yyy() {
//修改数据
}
爷孙传递:可以传两次 props
React 只是视图层框架,若是多层级组件传递,通过传递多次 props ,会变得难以维护,所以出现了 Redux (数据层框架)
Redux 是什么,如何用
把组件中的数据放到 Store 中,通过组件修改了 Store 中的数据,其他组件也会感知到数据的变化,从而做出更新,Redux 是状态容器,提供可预测化的状态管理。
工作流程
引用图书馆场景
React Component:借书的用户
Action Creators: 借什么书(这句话)
Store:图书馆管理员
Reducers: 记录本(书籍的记录)
小A(React Component)对图书馆管理员(Store)说:借一本 '三体'(Action Creators),管理员通过记录本(Reducers)去找这本书,找到之后把书给到小A
- 获取数据:一个组件去获取 Store 中的数据,对 Store 说:我要获取XX数据(Action Creators创建这句话),Store 接收到后,通过 Reducers 去找到这条数据,然后把数据给到这个组件
- 改变数据:同理 Store 通过 Reducers 知道如何改变数据,然后 Stroe 修改好数据后,告诉组件数据已修改,可以重新获取数据了
代码演示
Reducer 的创建(管理数据)
//store/reducer.js
const defaultState = {
inputValue: '',
list: []
}
export default (state = defaultState, action) => { //state 默认数据/上一次的数据
//拿之前的数据及 action 做处理,返回新的数据给 store
if (action.type === 'change_input_value') {
const newState = JSON.parse(JSON.stringify(state)) //之前的数据深拷贝
newState.inputValue = action.value //改变为传递过来的新值
return newState //传递给 store, 新旧数据做替换
}
return state
}
Store 的创建(存贮数据)
//store/index.js
import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
组件获取数据
import store from './store/index.js'
constructor(props) {
super(props)
this.state = store.getState() //获取 store 中的数据
}
<div>
{this.state.list}
</div>
修改数据:Action 的创建与派发
const action = {
type: 'change_input_value',
value: e.target.value
}
store.dispatch(action) //把 action 传递给 store
Store 再把当前数据及 action 转发给 Reducers 去处理,处理完后,store 中的数据会更新
组件中用到此数据的会自动更新
constructor(props) {
super(props)
store.subscribe(this.xxx.bind(this)) //只要 store 中的数据发生改变,subscribe 中的 xxx 会自动执行
}
connect 的原理是什么?
react-redux 库提供的一个 API,connect 的作用是让你把组件和store连接起来,产生一个新的组件(connect 是高阶组件)
React 有哪些生命周期函数?分别有什么用?
其他钩子可以不存在,但是 render 函数必须存在,否则会报错,因为组件是继承自 Component 组件,Component 组件默认内置了所有的声明周期钩子,但没有内置 render
在 componentDidMount 这个钩子里请求数据
放在 render 里不合适,render会被反复执行(数据会被频繁改变),此时会重复发送数据请求。
componentDidMount 在组件被挂载到页面上时会执行一次,之后不会再重复执行,所以把数据请求放到这里是比较合适的
componentWillMount 也会执行一次,写网页时,数据请求放到这里也是可以的,但是当写 React Native ,或服务端同构时,可能会产生技术冲突
shouldComponentUpdate 有什么用?(使用场景)
父组件渲染时(数据发生改变),因为父组件中的 render 函数包含子组件内容,所以子组件也跟着重复渲染,但是子组件中的 state, props 没有发生变化,会带来性能上的损耗,如何优化呢
子组件中使用 shouldComponentUpdate 钩子
class TodoItem extends Component {
//...
shouldComponentUpdate(nextProps, nextState) {
//接下来的 content 不等于当前 props 中的 content 说明接收的 content 值发生了变化,需要让组件重新渲染
if(nextProps.content !== this.props.content) {
return true
}else {
return false
}
}
render() {
const { content } = this.props
return (
<div>
{content}
</div>
)
}
}
用于在没有必要更新 UI 的时候返回 false,以提高渲染性能
其他提高性能的方法
- 改变 this,放到 constructor 里,这个操作只会执行一次
constructor(props) {
super(props)
this.xxx = this.xxx.bind(this)
}
2. setState 异步执行,多次数据的改变变成一次来做,降低虚拟 dom 比对的频率
标签: React
还木有评论哦,快来抢沙发吧~