redux-thunk的作用?
作用: 之前理解是用于接收中间件,后面发现不是的,是创建函数和网络请求的结合,而且在action本来返回对象的前提下,可以返回函数,这个函数通过middleware执行,可以带副作用,例如异步的api请求
// 在小程序中,我用到了await来进行同步操作api请求,后面通过then后进行返回dispatch
// 这里少了catch会不会被捕捉异步错误?会但是不体现在返回值
export const getActivities = () => {
// redux thunk 中间件允许这种形式
return async dispatch => {
if (!Taro.getStorageSync('canteen_id')) {
return;
}
await fapi.request({
url: api.activity(),
method: 'POST',
data: {
shopId: Taro.getStorageSync('canteen_id')
}
}).then((res) => {
let activities = res.data;
dispatch({
type: GET_ACTIVITY,
payload: {
activities
}
})
});
}
}
关于fapi的请求,await 之后如果没有catch最后也是返回undefined,只不过中间会把异常错误那些抛出来,像这里的await 最后无论结果如何都是undefined,
await new Promise(function(resolve, reject) {
// setTimeout(function() { console.log('异步'); resolve('异步') }, 1000);
throw Error('error');
}).then((res) => {
console.log('then', res);
return res;
}).catch((res) => {
console.log('catch', res);
})
关于创建action creator 的时候为啥是用展开运算符
Object.assign写起来减低了可读性,用...将可枚举的属性拷贝到另一个对象。
export default function good(state = INITIAL_GOOD_STATE, action: IGoodAction) {
switch (action.type) {
case GET_CURRENT_GOOD:
return {
...state,
...action.payload.good
};
default:
return state;
}
}
简单描述下Action,reducers, connect,store的关系
action主要还是用于操作数据,唯一操作数据的方式,
store就是主的数据树,统一管理一个store
reducers就是把这几个数据修改的函数定义好规则,统一操作,来决定每个action改变应用的state,函数叫函数
connect是react-redux是功能,把react的class组件的props数据与store关联起来
而之前所问题所提到的connect是通过proxy的方式来关联的,这个就要对源码进行分析才有作用了。
经常在action createor用到await, async
在通过action createor方式管理数据的时候,我经常用用到 async, await 语法糖这个本身会不会有问题,通过await dispatch来调用其实就是一个全局的方法,但是官方一直用到的是非await,这个有什么影响么,因为业务还是同步的比较多
export const getCoupons = (logingEvent = true) => {
return async dispatch => {
if (logingEvent) {
Taro.showLoading({
'title': ''
});
}
await fapi.request({
url: api.coupons(),
method: 'POST',
data: {
}
}).then((res) => {
if (logingEvent) {
Taro.hideLoading();
}
let coupons = res.data;
dispatch({
type: GET_COUPONS,
payload: {
coupons
}
})
});
}
}
loading的方式主要还是通过嵌入到dispatch来实现,有其它比较好的方式嘛
没想到,使用react-action来规范自己的action创建方式是一个路径,至于loading不知道能不能在中间件层级就做个注入判断,标记好方法需要 loading,到完成的时候hideloading,暂未找到这种中间件
reducer的格式自动转为type, payload。
react-action使用
const { increment, decrement } = createActions({
INCREMENT: (amount = 1) => ({ amount }),
DECREMENT: (amount = 1) => ({ amount: -amount })
});
// const options = {
// prefix: 'counter',
// namespace: '--'
// };
const rootReducer = handleActions(
{
// [noop]: (state, action) => ({
// counter: state.counter + action.payload,
// amount: state.amount
// }),
[combineActions(increment, decrement)]: (
state,
{ payload: { amount } }
) => {
return { ...state, counter: state.counter + amount };
}
},
{ counter: 10, amount: 10 }
// options
);
const middlewares = [reduxThunk];
middlewares.push(require('redux-logger').createLogger());
const createStoreWithMiddleware = applyMiddleware(...middlewares)(
createStore
);
const store = createStoreWithMiddleware(rootReducer);
var test = rootReducer({ counter: 5 }, increment(10));
console.log('rootReducer test', test);
console.log('increment()', increment());
store.dispatch(increment(30));
组织redux语义的时候为啥以type: xxxx, payload: xxxx为主, 通过action的来管理一些store的数据请求外数据处理的案例为啥很少
Immutable对象到底是啥东西?持久化数据结构
immutable.js是一个js库?
不可变集合,
采用了结构共享
主要通过Map,List来实现,而不是通过对象数组等结构?
js里有Set,这里的map是不是用set来实现的,List如果是数组又不是对象数组
只能看源码了解,暂时用到的是
比PureComponent好用?浅比较,immutable提供is方法,比较对象是否完全相同
import { is } from 'immutable';
shouldComponentUpdate(nextProps, nextState){
return !(this.props === nextProps || is(this.props, nextProps)) ||
!(this.state === nextState || is(this.state, nextState));
}
memoizationd技术,仅在输入变化的时候,才去重新计算render需要的值
比pureComponent的优化处在哪里呢。在过滤很大的列表,pureComponent这样做的效率不是很好 。但prop改变的时候pureComponent不会阻止再次渲染。
最终就会回到Concurrent Mode。引用朋友的问题。concurrent model模式,为啥推出这个模式,解决啥问题?现有模式与之前的模式的使用上的区别?
对中断渲染,加载顺序,并发处理多状态的模式
不让对多个组件并发请求的数据不知道怎么控制,或者当个组件的多个请求顺序执行还是并发执行控制。
应该只是一种方法模式来解决这类方法
目前特性suspense的是在legacy模式里可以使用,能用它来解决并发问题?
所以这个模式是具体做了什么,没文章体现
dan的视频中有提到,
react.renderToString是可以发送响应前渲染html?
服务端先渲染react?
shouldComponentUpdate与componentMidUpdate区别
shouldComponentUpdate是会影响render的组件函数,生命周期?如果shouldComponentUpdate的返回是false的话会影响render的更新,主要是浅比较,用于当props和之前props不同的情况?
componentMidUpdate是组件的props发生变化的时候,会触发,一定要加判断逻辑,防止出现死循环
新的getDerivedStateFromProps是啥意思【生命周期。。。】
只有一个目的: 让组件在props变化的时候更新state
利用这个生命周期,可以在渲染props之前清理旧数据
static getDerivedStateFromProps(props, state) {
if (props.currentRow !== state.lastRow) {
return {
isScrollingDown: props.currentRow > state.lastRow,
lastRow: props.currentRow,
};
}
// 返回 null 表示无需更新 state。
return null;
}
// 2
static getDerivedStateFromProp(props, state) {
if (props.id != state.prevId) {
return {
externalData: null,
prevId: props.id,
}
}
return null;
}
旧的componentWillReceiveProps是啥意思
getDerivedStateFromProps以前的旧方法,现已废弃
异步情况下,为啥值使用compoentDidUpdate 而不是compoentWillUpdate?
compoentDipUpdate保证每次更新值调用一次
redux生态下的包是指其它redux方面的包,不提供UMD 文件是啥意思?
就是页面上的script标签引入UMD文件
react-redux 的connect用到 Proxy来进行订阅发布?
不是,源码中没有proxy,connect是使用什么来进行store的管理?
看了源码了解到是重新用useMemo,useContent,useRef等钩子来进行构建管理store与props的关系~
/* connect is a facade over connectAdvanced. It turns its args into a compatible
selectorFactory, which has the signature:
(dispatch, options) => (nextState, nextOwnProps) => nextFinalProps
connect passes its args to connectAdvanced as options, which will in turn pass them to
selectorFactory each time a Connect component instance is instantiated or hot reloaded.
selectorFactory returns a final props selector from its mapStateToProps,
mapStateToPropsFactories, mapDispatchToProps, mapDispatchToPropsFactories, mergeProps,
mergePropsFactories, and pure args.
The resulting final props selector is called by the Connect component instance whenever
it receives new props or store state.
*/
selectorFactory is a func that is responsible for returning the selector function used to
compute new props from state, props, and dispatch. For example:
export default connectAdvanced((dispatch, options) => (state, props) => ({
thing: state.things[props.thingId],
saveThing: fields => dispatch(actionCreators.saveThing(props.thingId, fields)),
}))(YourComponent)
Access to dispatch is provided to the factory so selectorFactories can bind actionCreators
outside of their selector as an optimization. Options passed to connectAdvanced are passed to
the selectorFactory, along with displayName and WrappedComponent, as the second argument.
Note that selectorFactory is responsible for all caching/memoization of inbound and outbound
props. Do not use connectAdvanced directly without memoizing results between calls to your
selector, otherwise the Connect component will re-render on every state or props change.
coonnectAdvanced中的函数subscribeUpdatesr中的checkForUpdates,来更新,每个更新到就会调用这个函数
We'll run this callback every time a store subscription update propagates to this component
此外还封装了一个订阅函数组件连接到store的。确保后续组件的嵌套订阅。
import { getBatch } from './batch'
// encapsulates the subscription logic for connecting a component to the redux store, as
// well as nesting subscriptions of descendant components, so that we can ensure the
// ancestor components re-render before descendants
const nullListeners = { notify() {} }
function createListenerCollection() {
const batch = getBatch()
let first = null
let last = null
return {
clear() {
first = null
last = null
},
notify() {
batch(() => {
let listener = first
while (listener) {
listener.callback()
listener = listener.next
}
})
},
get() {
let listeners = []
let listener = first
while (listener) {
listeners.push(listener)
listener = listener.next
}
return listeners
},
subscribe(callback) {
let isSubscribed = true
let listener = (last = {
callback,
next: null,
prev: last,
})
if (listener.prev) {
listener.prev.next = listener
} else {
first = listener
}
return function unsubscribe() {
if (!isSubscribed || first === null) return
isSubscribed = false
if (listener.next) {
listener.next.prev = listener.prev
} else {
last = listener.prev
}
if (listener.prev) {
listener.prev.next = listener.next
} else {
first = listener.next
}
}
},
}
}
export default class Subscription {
constructor(store, parentSub) {
this.store = store
this.parentSub = parentSub
this.unsubscribe = null
this.listeners = nullListeners
this.handleChangeWrapper = this.handleChangeWrapper.bind(this)
}
addNestedSub(listener) {
this.trySubscribe()
return this.listeners.subscribe(listener)
}
notifyNestedSubs() {
this.listeners.notify()
}
handleChangeWrapper() {
if (this.onStateChange) {
this.onStateChange()
}
}
isSubscribed() {
return Boolean(this.unsubscribe)
}
trySubscribe() {
if (!this.unsubscribe) {
this.unsubscribe = this.parentSub
? this.parentSub.addNestedSub(this.handleChangeWrapper)
: this.store.subscribe(this.handleChangeWrapper)
this.listeners = createListenerCollection()
}
}
tryUnsubscribe() {
if (this.unsubscribe) {
this.unsubscribe()
this.unsubscribe = null
this.listeners.clear()
this.listeners = nullListeners
}
}
}
react经常也会提到babel-polyfill,babel-polyfill到底作用是啥?
有些不支持es6的地方,通过babel把那些函数转换成es5,babel-polyfill是其中的一种方式
首先babel有preset预设【插件和配置的共享集?】与插件plugin两块
预设中env和@babel/preset-env的区别:第二个是编译es6写法,而且属于智能性预设,可以结合babel-polyfile一起使用,第一个env就是babel-preset-env 本质上是一样的
@babel/preset-env是用来过渡preset-laster
- 预设一般是我们经常会设置的
{
"preset": "env"
}
- 插件
如果设置了bable-preset-env默认与babel-preset-laster的行为相同?
关于stage-0, stage-1, stage-2, stage-3 四个提案
三个不同的提案对于babel的影响是怎么样呢
暂不清楚,只知道有stage-0这些东西。
针对于react hook优势来说未来 react的方向,比起传统的class方式的优势在哪里,userEffect与componentDidMount区别?
- 不用管理复杂的生命周期
- 事件的注销不用在对应的生命周期操作
- 节约代码,更细化的切分业务,不会像class那样管理一个总的对象state,通过自定义的hook,切割不同的state业务操作。
- 函数嵌套太深
- 组件太大 huge components
- 困惑的class confusing classes
引用朋友的问题,react hook,用链表实现,如果是你会怎么实现?
首先要搞清楚,是哪里用到链表
react hook 的useState就用到了。
问题1, state更新的时候,以什么方式更新,重新渲染整个dom?
是重新渲染,更新方式。
组件构建的Hooks链表会挂载到FiberNode节点的memoizedState上
每个Hook节点通过循环链表记住所有的更新操作
问题2,两个state怎么管理,在useState里面,怎么知道是更新哪个state?通过赋值变量,如果我变量变化了怎么通知useEffect更新?
在update阶段会依次执行update循环链表中的所有更新操作,最终拿到最新的state返回
所以这里不能条件语句里加hook,
会怎么实现?
react hook 的useState 异步回调获取不到最新值及解决方案
1
Promise.resolve().then(() => {
setArr(prevState => [...prevState, 1]); // 这里也可以不改,使用第一中传参方式 setArr([...arr, 1]); 因为这里不需要获取最新状态
})
.then(() => {
setArr(prevState => [...prevState, 2]); // 这里必须改成回调函数传参方式,否则会读取旧状态,导致异常
})
2
const [, forceUpdate] = useReducer(x => x + 1, 0);
3
const [arr, setArr] = useState([0]);
let ref = useRef();
useEffect(() => {
ref.current = arr;
console.log(arr);
});
const handleClick = () => {
Promise.resolve().then(() => {
const now = [...ref.current, 1];
ref.current = now;
setArr(now);
})
.then(() => {
setArr([...ref.current, 2]);
});
}
react hook,useEffect中->How to fix missing dependency warning when using useEffect React Hook
stackoverflow.com/questions/5…
何为Memoization, 为啥useCallback是memoization回调函数。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
fiber是啥,为何在react中出现,并且应用是啥?
fiber 之前是递归对比虚拟dom数,这个过程叫协调,后面采用fiber。
一种数据结构,链表实现,react hook也是基于链表。
查询的时候已经不在是递归,而是用过这种架构来查找对应的节点。
用到requestAnimationFrame,requestIdleCallback
react采用fiber,vue呢,vue是基于template,warcher进行组件更新,每个任务分割的足够小?不用用到fiber架构
ts中never的作用是?
interface a {
type: 'a'
}
interface b {
type: 'b'
}
type ALL = a | b;
// 或许ALL又有新增的c类型,忘记在
function change(val: ALL) {
switch(val) {
case 'a':
break;
case 'b':
break;
default:
const exhaustiveCheck: never = val
break;
}
}
// 出现类型c,就会出现编译错误,确保穷尽change的方法
swr的作用在于哪里?(stale-while-revalidate)
useRequest?可以做缓存,但是不知道怎么做到缓存,基于文件存储还是什么存储还是不清楚
- http rfc 5861标准中的一种缓存更新策略
使用requestIdleCallback这个API来进行操作
requestAnimationFrame
React.Fc<函数组件>是什么意思
typescript使用的一个泛型
FC是函数组件的意思
[