<Twitter username='tylermcginnis33'>
{(user) => user === null
? <Loading />
: <Badge info={user} />}
</Twitter>
import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
// fetchUser take in a username returns a promise
// which will resolve with that username's data.
class Twitter extends Component {
// finish this
}
combineReducers 函数主要用来接收一个对象,将参数过滤后返回一个函数。该函数里有一个过滤参数后的对象 finalReducers,遍历该对象,然后执行对象中的每一个 reducer 函数,最后将新的 state 返回
介绍Redux数据流的流程
view 到 redux 的过程中会派发一个 action , action 通过 Store 的 dispatch 方法,会派发给 store , store接收到 action ,再连同之前的 state 一起传给 reducer , reducer 返回一个新的数据给 store , store 就可以去改变自己的 state ,组件接收到新的 state 就可以重新渲染页面了
其中,redux有三个基本属性,Action,Reducer,Store
Action 是把数据从应用传到 store 的有效载体,也是 store 数据的唯一来源,用法是通过 store.dispatch() 把 action 传到 store。(Action 只是描述了有事情发生了这一事实,并没有指明应用如何更新 state。)
这是 reducer 要做的事情。reducer 负责管理整个业务里边的数据,包括处理数据,存储数据等。刚刚说了store.dispatch() 会把 action 传到 store ,但是store并不知道怎么处理这个数据,需要去 reducer 进行查找,所以需要把当前 store 里存在的数据和接收的 action 转给 reducer , reducer 处理好了之后再转给 store。reducer 返回的必须是一个函数,这个函数里面接收两个参数,一个是 state ,另一个是 action。
既然可以使用 action 来描述“发生了什么”,使用 reducers 来根据 action 更新 state 的用法。那Store 就是把它们联系到一起的对象,它负责存储项目应用中的所有数据,通过redux的createStore()方法创建store公共数据存储区域,然后把 reducer 传给 store,就可以在 reducer 中查看数据并做处理,const store = createStore(reducer)
Store提供了一些方法。让我们很方便的操作数据:
维持应用的 state
提供 getState() 方法获取 store 的数据内容state
提供 dispatch(action) 方法派发 action ,更新 state
通过 subscribe(listener) 注册监听器,订阅 store 的改变,只要 store 发生改变, store.subscrible 这个函数接收的这个回调函数就会被执行
虚拟DOM是啥?以及diff算法原理
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能 原理:
diff算法,DOM树对比过程
https://github.com/lulujianglab/blog/issues/46
为什么虚拟 dom 会提高性能?
虚拟DOM提高性能,不是说不操作DOM,而是减少操作DOM的次数,减少回流和重绘 虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能
使用diff算法比较新旧虚拟DOM----即比较两个js对象不怎么耗性能,而比较两个真实的DOM比较耗性能,从而虚拟DOM极大的提升了性能
虚拟DOM的目的?
实现页面中DOM元素的高效更新
虚拟DOM会比真实DOM快吗?什么情况下用虚拟DOM好
虚拟DOM并不一定比原生操作DOM快。需不需要虚拟DOM,其实与框架的DOM操作机制有关 React 的基本思维模式是每次有变动就重新渲染整个应用。如果没有 Virtual DOM,简单来想就是直接重置 innerHTML。 比如,在一个大型列表所有数据都变了的情况下,重置 innerHTML 其实是一个还算合理的操作... 真正的问题是在 “全部重新渲染” 的思维模式下,即使只有一行数据变了,它也需要重置整个 innerHTML,这时候显然就有大量的浪费。
可以比较一下 innerHTML vs. Virtual DOM 的重绘性能消耗:
Virtual DOM render + diff 显然比渲染 html 字符串要慢,但是!它依然是纯 js 层面的计算,比起patch简化的dom操作省下来的时间可观的多。 可以看到,innerHTML 的总计算量是和整个界面的大小相关,但 Virtual DOM 的计算量里面,只有 js 计算和界面大小相关,DOM 操作是和数据的变动量相关的。和 DOM 操作比起来,js 计算是极其快速的。 这才是为什么要有 Virtual DOM:它保证了 1)不管你的数据变化多少,每次重绘的性能都可以接受; 2) 你依然可以用类似 innerHTML 的思路去写你的应用。
这也是 React 厉害的地方。并不是说它比 DOM 快,而是说不管你数据怎么变化,我都可以以最小的代价来进行更新 DOM。 方法就是我在内存里面用新的数据重新生成一个虚拟 DOM 树,然后比较新旧 DOM,找出差异,再更新到 DOM 树上。这就是所谓的 diff 算法
react是怎么工作的,怎么提高性能
主要还是说了下react的生命周期,还有shouldComponentUpdate这个函数,以及diff算法 https://github.com/lulujianglab/blog/issues/47
React 的工作原理
React 会创建一个虚拟 DOM(virtual DOM)。当一个组件中的状态改变时,React 首先会通过 "diffing" 算法来标记虚拟 DOM 中的改变,第二步是调节(reconciliation),会用 diff 的结果来更新 DOM
react 事件绑定
由于类的方法默认不会绑定this,因此在调用的时候如果忘记绑定,this的值将会是undefined。 绑定方式有以下几种:
比较:
方式2和方式3都是在调用的时候再绑定this
方式1在类构造函数中绑定this,调用的时候不需要再绑定
利用属性初始化语法(箭头函数声明),将方法初始化为箭头函数,因此在创建函数的时候就绑定了this(只会生成一个)
方式1是官方推荐的绑定方式,也是性能最好的方式。方式2和方式3会有性能影响并且当方法作为属性传递给子组件的时候会引起重渲问题。方式4目前是最好的绑定方式,需要结合bable转译 this 的本质就是:this跟作用域无关的,只跟执行上下文有关
生命周期
函数式编程,纯函数
React创建组件的方式
React 中有三种构建组件的方式 React.createClass()、ES6 class 和无状态函数
组件性能优化
shouldComponentUpdate(react 性能优化是哪个周期函数?)
这个方法用来判断是否需要调用 render 方法重新描绘 dom。 因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。
pureComponent
不可变数据
key
等等优化方法,每一点的优点和缺点
如何设计一个好组件?容器组件和展示组件
合理划分组件,分为业务组件和技术组件
调用setState之后发生了什么
refs的作用
Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。 我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回
上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用。 另外值得一提的是,refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值:
如果你创建了类似于下面的 Twitter 元素,那么它相关的类定义是啥样子的?
回调渲染模式:这种模式中,组件会接收某个函数作为其子组件,然后在渲染函数中以 props.children 进行调用
这种模式的优势在于将父组件与子组件解耦和,父组件可以直接访问子组件的内部状态而不需要再通过 Props 传递,这样父组件能够更为方便地控制子组件展示的 UI 界面
譬如产品经理让我们将原本展示的 Badge 替换为 Profile,我们可以轻易地修改下回调函数
何为 Children
展示组件(Presentational component)和容器组件(Container component)之间有何不同
类组件(Class component)和函数式组件(Functional component)之间有何不同
(组件的)状态(state)和属性(props)之间有何不同
何为受控组件(controlled component)
<input>
,<textarea>
和<select>
这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。<Input placeholder="请输入" value={inputValue.trim()} onChange={this.handleChangeValue} onPressEnter={this.handleSearch} />
如果只是通过回调去实现,只能立即获取上一步修改后的结果
demo-01:
demo-02:
React 其实会维护着一个 state 的更新队列,每次调用 setState 都会先把当前修改的 state 推进这个队列,在最后,React 会对这个队列进行合并处理,然后去执行回调。根据最终的合并结果再去走下面的流程(更新虚拟dom,触发渲染)
setState为什么要设计成异步的?react的setState同步还是异步?
(在构造函数中)调用 super(props) 的目的是什么
在 super() 被调用之前,子类是不能使用 this 的,在 ES6 中,子类必须在 constructor 中调用 super()。 传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props
如何实现异步网络请求的?应该在 React 组件的何处发起 Ajax 请求,为什么
在 React 组件中,应该在 componentDidMount 中发起网络请求。 这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。 如果在之前发起请求,可能在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,将不起作用。在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
react16新特性
尤其理解time slice和suspense
在 React 当中 Element 和 Component 有何区别
简单地说,一个 React element 描述了你想在屏幕上看到什么。换个说法就是,一个 React element 是一些 UI 的对象表示。
一个 React Component 是一个函数或一个类,它可以接受输入并返回一个 React element t(通常是通过 JSX ,它被转化成一个 createElement 调用)
路由实现原理
react-router等一众路由插件实现的功能是更新页面的视图,但是却不重新请求页面,也就是说,其实,他们并没有实际进行了跳转,而是修改了页面的DOM并通过修改页面的URL来模拟跳转 在HTML5之前,页面路由只有hash模式,而HTML5中History对象的新增方法,带来了另一种模式:history模式
hash模式: 在HTML5之前,vue-router是通过修改URL的hash值来达到修改页面URL并生成历史记录,虽然不会重新请求页面,但会发现路径前总会有一个#,比如
http://localhost:8080/#/b
因为没开启history模式的情况下,vue-router是通过hashchange事件来监听URL中hash的改变并通过修改hash来模拟路径的变化 hash模式最大的优点是兼容性强,可以兼容一众老式浏览器。而它最大的缺点是,页面URL中一直挂着一个难看的#history模式: HTML5发布后,又有了history模式 vue-router的history模式就是通过HTML5中History对象的pushState方法进行模拟的 HTML5还提供了一个popstate事件,当用户点击前进、后退按钮,或者调用back、forward、go方法时触发,可以监听URL的改变 不仅如此,还可以使用pushState的第一个参数进行传值,使用History的state属性进行取值。 但是目前只有兼容了HTML5的浏览器(IE10+)才能使用history模式
简述 flux 思想
Flux 的最大特点,就是数据的"单向流动"。
React 项目用过什么脚手架
redux 有什么缺点
组件间通信
React key是干嘛的?
Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识
说一下 redux ,redux、react-redux等原理
https://github.com/lulujianglab/blog/issues/34
基本思想
整个应用的 state 保持在一个单一的 store 中 改变应用 state 的唯一方式是在应用中触发 actions,然后为这些 actions 编写 reducers 来修改 state
store
Store 是一个 javascript 对象,它保存了整个应用的 state。与此同时,Store 也承担以下职责:
action
Actions 是一个纯 javascript 对象,它们必须有一个 type 属性表明正在执行的 action 的类型。实质上,action 是将数据从应用程序发送到 store 的有效载荷
reducer
一个 reducer 是一个纯函数,该函数以先前的 state 和一个 action 作为参数,并返回下一个 state
Redux Thunk 的作用是什么
Redux thunk 是一个允许你编写返回一个函数而不是一个 action 的 actions creators 的中间件。如果满足某个条件,thunk 则可以用来延迟 action 的派发(dispatch),这可以处理异步 action 的派发(dispatch)
何为纯函数(pure function)
一个纯函数是一个不依赖于且不改变其作用域之外的变量状态的函数,这也意味着一个纯函数对于同样的参数总是返回同样的结果
combineReducers
combineReducers 函数主要用来接收一个对象,将参数过滤后返回一个函数。该函数里有一个过滤参数后的对象 finalReducers,遍历该对象,然后执行对象中的每一个 reducer 函数,最后将新的 state 返回
介绍Redux数据流的流程
view 到 redux 的过程中会派发一个 action , action 通过 Store 的 dispatch 方法,会派发给 store , store接收到 action ,再连同之前的 state 一起传给 reducer , reducer 返回一个新的数据给 store , store 就可以去改变自己的 state ,组件接收到新的 state 就可以重新渲染页面了
其中,redux有三个基本属性,Action,Reducer,Store
const store = createStore(reducer)
Store提供了一些方法。让我们很方便的操作数据:Redux如何实现多个组件之间的通信,多个组件使用相同状态如何进行管理
react-redux(Provider 传入到最外层组件store 在需要用到的地方 用 connect 获取 (mapStateToProps, mapDispatchToProps) 在页面中引用) 类似发布订阅模式, 一个地方修改了这个值, 其他所有使用了这个相同状态的地方也会更改
多个组件之间如何拆分各自的state,每块小的组件有自己的状态,它们之间还有一些公共的状态需要维护,如何思考这块
在实际项目开发中,如果 reducer 存放过多的数据,可能会造成代码的不可维护,我们需要把总的 reducer 拆分为多个子的 reducer,然后再做一个整合。 一个全局的 reducer , 页面级别的 reducer , 然后redux 里有个 combineReducers 把所有的 reducer 合在一起,小组件的使用与全局的使用是分开的互不影响
然后在页面中通过
state.header.focused
访问使用过的Redux中间件
react-redux React-Redux是 redux官方提供的 React 绑定库,可以在 react 中非常方便是使用 redux React-redux有两个核心方法。一个是Provider,另一个是connect
redux-thunk(把action 返回的对象 换成一个异步函数) :
因为reducer 必须是纯函数,是不能进行ajax这种异步操作的,而在组件中直接进行ajax异步操作或者复杂的业务逻辑处理,组件会显得过于臃肿。 有了redux-thunk,就可以将ajax异步请求或者是复杂的逻辑放到 action 去处理,原则上 action 返回的是一个对象,但当我们使用 redux-thunk 中间件后, action 就可以返回一个函数了,继而可以在函数里边进行异步操作,也就可以把组件中获取数据的请求放入这个函数中了
redux-saga 虽然redux-thunk可以接受函数作为action,但函数的内部如果有多个异步操作,就需要为每一个异步操作都定义一个action,异步操作太为分散而不易维护 这个时候就可以用到redux-saga。 redux-saga也是做异步代码拆分的,可以完全替代 redux-thunk 。 要通过redux-saga的createSagaMiddleware()方法创建saga中间件,还需要有一个sagajs文件,这样通过sagaMiddleware.run(mySaga)来运行这个sagas文件,这样当组件dispatch一个action的时候,不仅reducer可以接收到,sagas文件中也可以接收到了
sagajs导出的是个生成器函数,通过在生成器函数中使用takeEvery方法,捕捉派发出来的所有 action。takeEvery有两个参数,第一个参数时action type,第二个参数是函数,一旦接收到符合条件的 action type,就执行第二个参数方法,所以就可以把异步逻辑写到这个方法里集中处理了,这个方法中有一个put方法也可以派发action操作。类似于 redux 原始的 dispatch,都可以发出 action,且发出的 action 都会被 reducer 监听到
redux-saga 远比 redux-thunk 复杂的多, redux-saga 里边有非常多的api,我们只用了 takeEvery 、 put ,官方文档中还有很多我们经常用到的 call 、 takeLatest 等,在处理大型项目时, redux-saga 是要优于 redux-thunk 的;但是从另一角度来说, redux-thunk 几乎没有任何 api ,特点就是在 action 里面返回的内容不仅仅是个对象,还可以是个函数
只要使用了中间件,就需要使用
applyMiddleware()
函数,顾名思义,是运行中间件的函数。它是Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。 中间件就是指的 dispatch 方法的一个封装或者升级。(redux-thunk中间件:对 dispatch 方法做了封装之后,既可以接收对象,又可以接收函数了)所以中间件本质上只是拓展了store.dispatch方法