(reducer, initialState, init)
| 180 | * @returns {[ S, (state: S) => void ]} |
| 181 | */ |
| 182 | export function useReducer(reducer, initialState, init) { |
| 183 | /** @type {import('./internal').ReducerHookState} */ |
| 184 | const hookState = getHookState(currentIndex++, 2); |
| 185 | hookState._reducer = reducer; |
| 186 | if (!hookState._component) { |
| 187 | hookState._value = [ |
| 188 | !init ? invokeOrReturn(undefined, initialState) : init(initialState), |
| 189 | |
| 190 | action => { |
| 191 | const currentValue = hookState._nextValue |
| 192 | ? hookState._nextValue[0] |
| 193 | : hookState._value[0]; |
| 194 | const nextValue = hookState._reducer(currentValue, action); |
| 195 | |
| 196 | if (currentValue !== nextValue) { |
| 197 | hookState._nextValue = [nextValue, hookState._value[1]]; |
| 198 | hookState._component.setState({}); |
| 199 | } |
| 200 | } |
| 201 | ]; |
| 202 | |
| 203 | hookState._component = currentComponent; |
| 204 | |
| 205 | if (!currentComponent._hasScuFromHooks) { |
| 206 | currentComponent._hasScuFromHooks = true; |
| 207 | let prevScu = currentComponent.shouldComponentUpdate; |
| 208 | const prevCWU = currentComponent.componentWillUpdate; |
| 209 | |
| 210 | // If we're dealing with a forced update `shouldComponentUpdate` will |
| 211 | // not be called. But we use that to update the hook values, so we |
| 212 | // need to call it. |
| 213 | currentComponent.componentWillUpdate = function (p, s, c) { |
| 214 | if (this._force) { |
| 215 | let tmp = prevScu; |
| 216 | // Clear to avoid other sCU hooks from being called |
| 217 | prevScu = undefined; |
| 218 | updateHookState(p, s, c); |
| 219 | prevScu = tmp; |
| 220 | } |
| 221 | |
| 222 | if (prevCWU) prevCWU.call(this, p, s, c); |
| 223 | }; |
| 224 | |
| 225 | // This SCU has the purpose of bailing out after repeated updates |
| 226 | // to stateful hooks. |
| 227 | // we store the next value in _nextValue[0] and keep doing that for all |
| 228 | // state setters, if we have next states and |
| 229 | // all next states within a component end up being equal to their original state |
| 230 | // we are safe to bail out for this specific component. |
| 231 | /** |
| 232 | * |
| 233 | * @type {import('./internal').Component["shouldComponentUpdate"]} |
| 234 | */ |
| 235 | // @ts-ignore - We don't use TS to downtranspile |
| 236 | // eslint-disable-next-line no-inner-declarations |
| 237 | function updateHookState(p, s, c) { |
| 238 | if (!hookState._component.__hooks) return true; |
| 239 |
searching dependent graphs…