《react.js小书》读书笔记三
《react.js》小书非常基础,适合入门新手,非常好理解,规定自己三天时间内阅读完并确保最基本的知识都掌握了,将一些平时回忽略的注意点做了小笔记和总结
《react.js小书》读书笔记一:
《react.js小书》读书笔记二:
在线阅读:http://huziketang.com/books/react/
在线OJ试题:http://scriptoj.mangojuice.top/problemsGroups/593a2e29b3838c385539fa4f
第三阶段
高阶函数
就是一个函数,传给它一个组件,它会返回一个新的组件
const NewComponeent = higherOrderComponent(OldComponent)
高阶组件是一个函数,而不是组件,他接受一个组件作为参数,返回一个新的组件
import React, { Component } from 'react' export default (WrappedComponent) => {
class NewComponent extents Component {
// 可以做很多自定义逻辑
render () {
return <WrappedComponent />
}
}
return NewComponent
}
现在给NewComponent 做一些数据启动工作
import React, { Component } from 'react'
export default (WrappedComponent, name) => {
class NewComponent extents Component {
constuctor (){
super()
this.state={ data:null }
}
componentWillMount () {
let data = localStorage.getItem(name)
this.setState({ data})
}
render () {
return <WrappedComponent data={this.state.data}/>
}
}
return NewComponent
}
高阶组件的作用其实是为了组件之间的代码复用,组件可能有着某些相同的逻辑,把这些逻辑抽离出来,放到高阶组件中进行复用。高阶组件内部的包装组件和被包装组件之间通过props传递数据。(其实就是设计模式中的装饰者模式)
context
某个组件只要往自己的context里面放了某些状态,这个组件之下的所有子组件都直接访问这个状态而不需要通过中间件的传递。(只有子组件可以访问,父组件不行)
redux
redux和react-redux不是同一个东西,redux是一种架构模式,是flux架构的变种,可以同react和vue等库结合,而react-redux就是redux与react.js结合起来的一个库
store
store是一个集合,使用createStore来专门生产state 和 dispatch,包含了如下几种方法:
function createStore (state, stateChanger) { const listeners = []
const getState = () => state
const subscribe = (listener) => listeners.push(listener)
const dispatch = (action) => {
stateChanger(state, action)
listeners.forEach((listener) => listener())
}
return { getState, dispatch, subscribe }
}
- getState 用于获取state数据,其实就是简单的把state参数返回
- subscribe 用来监听数据的变化
- dispatch 用于修改数据,接受一个action,可以根据action来修改state
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '《React.js 小书》' }) // 修改标题文本 store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色
纯函数:
函数的返回结果只依赖于它的参数
const a = 1 const foo = (b) => a+b
foo(2) // 3
//foo 不是一个纯函数,因为返回结果依赖于外部变量a
const foo2 = (x, b) => x + b
foo2(1,2) //3
//foo2是一个纯函数,因为只依赖于参数
函数执行过程没有副作用
consst a = 1 const foo = (obj, b) => {
return obj.x + b
}
const counter = { x : 1 }
foo(counter,2)
counter.x // 1
// foo 是一个纯函数,计算前后的counter并不会发生任何改变
const a = 1
const foo = (obj, b) => {
obj.x = 2
return obj.x + b
}
const counter = { x: 1 }
foo2(counter, 2) // => 4
counter.x // => 2
//foo2不是纯函数,计算前后counter发生了改变。
reducer
createStore接受一个叫reducer的函数作为参数,这个函数规定是一个纯函数,他接受两个参数,一个是state,一个是action。如果没有传入state或者state为null,那么他就会返回一个初始化的诗句,如果有传入state的话,那么就会根据action来修改数据,如果不能识别action,就不会产生新的数据,而是把state原封不动返回。
回顾redux
- 发现问题:如果共享数据状态可以被任意修改的话,那么程序行为将会不可预料
- 解决问题:提高修改数据的门槛,必须通过dispatch来执行某些允许的修改操作,并且在action里面声明(通过action中的type来判断是否允许修改)
- 优化方案:抽象出一个createStore,可以产生store,里面包含getState 和 dispatch函数.
function createStore( stateChanger) { let state = null
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
state = stateChanger(state, action) // 覆盖原对象
listeners.forEach((listener) => listener())
}
dispatch({}) // 初始化 state
return {
getState,
dispatch,
subscribe
}
}
- 发现问题: 每次修改数据都要手动渲染很麻烦.
- 解决问题: 加入了订阅者模式. store.subscribe订阅数据修改事件,每次数据更新会自动渲染
- 优化方案: 引入"共享结构的对象",在每个渲染函数开头进行简单的判断,避免没有被修改过的数据重新渲染
if (newAppState === oldAppState) return
- 优化方案: 优化了stateChanger为reducer,定义了reducer只能是纯函数,功能是负责初始化或者根据action.type修改state
//定义一个reducer function reducer (state, action) {
//初始化state 和 switch case 计算返回新state
}
//生成store
const store = createStore(reducer)
//监听数据变化重新渲染页面
store.subscribe(() => renderApp(store.getState()))
//后面可以随意dispatch了,页面自动更新
store.dispatch(......)
完整代码如下
function createStore( stateChanger) { let state = null
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
state = stateChanger(state, action) // 覆盖原对象
listeners.forEach((listener) => listener())
}
dispatch({}) // 初始化 state
return { getState, dispatch, subscribe}
}
function renderApp(newAppState, oldAppState = {}) {
if (newAppState === oldAppState) return // 数据没有变化就不渲染了
console.log('render app...')
renderTitle(newAppState.title, oldAppState.title)
renderContent(newAppState.content, oldAppState.content)
}
function renderTitle(newTitle, oldTitle = {}) {
console.log('render title...')
if (newTitle === oldTitle) return // 数据没有变化就不渲染了
const titleDOM = document.getElementById('title')
titleDOM.innerHTML = newTitle.text
titleDOM.style.color = newTitle.color
}
function renderContent(newContent, oldContent = {}) {
if (newContent === oldContent) return // 数据没有变化就不渲染了
console.log('render content...')
const contentDOM = document.getElementById('content')
contentDOM.innerHTML = newContent.text
contentDOM.style.color = newContent.color
}
function stateChanger (state, action) {
if (!state) {
return {
title: {
text: 'React.js 小书',
color: 'red',
},
content: {
text: 'React.js 小书内容',
color: 'blue'
}
}
}
switch (action.type) {
case 'UPDATE_TITLE_TEXT':
return {
...state,
title: {
...state.title,
text: action.text
}
}
case 'UPDATE_TITLE_COLOR':
return {
...state,
title: {
...state.title,
color: action.color
}
}
default:
return state
}
}
const store = createStore( stateChanger)
let oldState = store.getState() // 缓存旧的 state
store.subscribe(() => {
const newState = store.getState() // 数据可能变化,获取新的 state
renderApp(newState, oldState) // 把新旧的 state 传进去渲染
oldState = newState // 渲染完以后,新的 newState 变成了旧的 oldState,等待下一次数据变化重新渲染
})
renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: 'UPDATE_TITLE_TEXT',text: '《React.js 小书》'}) // 修改标题文本
store.dispatch({ type: 'UPDATE_TITLE_COLOR',color: 'blue'}) // 修改标题颜色
React-redux
- 高阶函数帮我们从context取数据,Dumb组件帮助我们提高组件的复用性.
- 用高阶组件包装Dumb,高阶组件和context打交道,把里面的数据取出来通过Props传给Dumb
- 这个高阶组件叫connect,接受一个组件作为参数,将从context里面取出的store通过props传给这个组件(如下图)
- 通过mapStateToProps告诉高阶组件我们需要什么数据,获取 整合状态
const mapStateToProps = ( state ) =>{ return{
themeColor:state.themeColor,
themeName:state.themeName
}
}
- 所以现在connect是接受一个参数mapStateToProps,然后返回一个高阶组件(也就是函数),它会接收一个组件作为参数,然后用Connect把组件包装以后再返回.
const mapStateToProps = (state) =>{ return {
themeColor:state.themeColor
}
}
Header = connect(mapStateToProps)(Header)
- 通过mapDispatchToProps告诉组件需要如何触发dispatch
总结过程
- 创建一个reducer
- 用createStore函数创建reducer的store
- 将store放在父组件的context中,子组件都可以访问
- 使用connect 将 store 和 context 结合起来
- connect接收两个参数(mapStateToProps,mapDispatchToProps),分别用于告诉connect需要什么数据和需要触发什么action
- Privider作为所有组件树的根节点,外界可以通过props给它提供store.
以上是 《react.js小书》读书笔记三 的全部内容, 来源链接: utcz.com/z/381344.html