From 21f7e46fda211cd32a56d67df6b8cfd52c81132f Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 30 Jul 2018 12:05:39 -0300 Subject: [PATCH 1/8] Started to the Portugues translation --- Framework/react-br.md | 572 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 572 insertions(+) create mode 100644 Framework/react-br.md diff --git a/Framework/react-br.md b/Framework/react-br.md new file mode 100644 index 00000000..4dcc4a6d --- /dev/null +++ b/Framework/react-br.md @@ -0,0 +1,572 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [React Lifecycle analysis](#react-lifecycle-analysis) + - [The usage advice of Lifecycle methods in React V16](#the-usage-advice-of--lifecycle-methods-in-react-v16) +- [setState](#setstate) +- [Redux Source Code Analysis](#redux-source-code-analysis) + + + +# Análise do Ciclo de vida React + +O Fiber foi introduzido no lançamento da V16. O mecanismo afeta alguma das chamadas do ciclo de vida até certo ponto e foi introduzida duas novas APIs para resolver problemas. + +Nas versões anteriores, se eu tiver um componente composto complexo e então mudar o `state` na camada mais alta do componente, a pilha de chamada poderia ser grande. + +![](https://user-gold-cdn.xitu.io/2018/6/25/164358b0310f476c?w=685&h=739&f=png&s=61462) + +If the call stack is too long, and complicated operations are performed in the middle, it may cause the main thread to be blocked for a long time, resulting in a bad user experience. Fiber is born to solve this problem. + +Fiber is essentially a virtual stack frame, and the new scheduler freely schedules these frames according to their priority, thereby changing the previous synchronous rendering to asynchronous rendering, and segmenting the update without affecting the experience. + +![](https://user-gold-cdn.xitu.io/2018/6/25/164358f89595d56f?w=1119&h=600&f=png&s=330885) + +React has its own set of logic on how to prioritize. For things that require high real-time performance, such as animation, which means it must be rendered once within 16 ms to ensure that it is not stuck, React pauses the update every 16 ms (within 16ms) and returns to continue rendering the animation. + +For asynchronous rendering, there are now two stages of rendering: `reconciliation` and `commit`. The former process can be interrupted, while the latter cannot be suspended, and the interface will be updated until it is completed. + +**Reconciliation** stage + +- `componentWillMount` +- `componentWillReceiveProps` +- `shouldComponentUpdate` +- `componentWillUpdate` + +**Commit** stage + +- `componentDidMount` +- `componentDidUpdate` +- `componentWillUnmount` + +Because the `reconciliation` phase can be interrupted, the lifecycle functions that will be executed in the `reconciliation` phase may be called multiple times, which may cause bugs. So for these functions, except for `shouldComponentUpdate`, should be avoided as much as possible, and a new API is introduced in V16 to solve this problem. + +`getDerivedStateFromProps` is used to replace `componentWillReceiveProps` , which is called during initialization and update + +```js +class ExampleComponent extends React.Component { + // Initialize state in constructor, + // Or with a property initializer. + state = {}; + + static getDerivedStateFromProps(nextProps, prevState) { + if (prevState.someMirroredValue !== nextProps.someValue) { + return { + derivedData: computeDerivedState(nextProps), + someMirroredValue: nextProps.someValue + }; + } + + // Return null to indicate no change to state. + return null; + } +} +``` + +`getSnapshotBeforeUpdate` is used to replace `componentWillUpdate`, which is called after the `update` but before the DOM update to read the latest DOM data. + +## The usage advice of Lifecycle methods in React V16 + +```js +class ExampleComponent extends React.Component { + // Used to initialize the state + constructor() {} + // Used to replace `componentWillReceiveProps` , which will be called when initializing and `update` + // Because the function is static, you can't get `this` + // If need to compare `prevProps`, you need to maintain it separately in `state` + static getDerivedStateFromProps(nextProps, prevState) {} + // Determine whether you need to update components, mostly for component performance optimization + shouldComponentUpdate(nextProps, nextState) {} + // Called after the component is mounted + // Can request or subscribe in this function + componentDidMount() {} + // Used to get the latest DOM data + getSnapshotBeforeUpdate() {} + // Component is about to be destroyed + // Can remove subscriptions, timers, etc. here + componentWillUnmount() {} + // Called after the component is destroyed + componentDidUnMount() {} + // Called after component update + componentDidUpdate() {} + // render component + render() {} + // The following functions are not recommended + UNSAFE_componentWillMount() {} + UNSAFE_componentWillUpdate(nextProps, nextState) {} + UNSAFE_componentWillReceiveProps(nextProps) {} +} +``` + +# setState + +`setState` is an API that is often used in React, but it has some problems that can lead to mistakes. The core reason is that the API is asynchronous. + +First, calling `setState` does not immediately cause a change to `state`, and if you call multiple `setState` at a time, the result may not be as you expect. + +```js +handle() { + // Initialize `count` to 0 + console.log(this.state.count) // -> 0 + this.setState({ count: this.state.count + 1 }) + this.setState({ count: this.state.count + 1 }) + this.setState({ count: this.state.count + 1 }) + console.log(this.state.count) // -> 0 +} +``` + +First, both prints are 0, because `setState` is an asynchronous API and will only execute after the sync code has finished running. The reason for `setState` is asynchronous is that `setState` may cause repainting of the DOM. If the call is repainted immediately after the call, the call will cause unnecessary performance loss. Designed to be asynchronous, you can put multiple calls into a queue and unify the update process when appropriate. + +Second, although `setState` is called three times, the value of `count` is still 1. Because multiple calls are merged into one, only `state` will change when the update ends, and three calls are equivalent to the following code. + +```js +Object.assign( + {}, + { count: this.state.count + 1 }, + { count: this.state.count + 1 }, + { count: this.state.count + 1 }, +) +``` + +Of course, you can also call `setState` three times by the following way to make `count` 3 + +```js +handle() { + this.setState((prevState) => ({ count: prevState.count + 1 })) + this.setState((prevState) => ({ count: prevState.count + 1 })) + this.setState((prevState) => ({ count: prevState.count + 1 })) +} +``` + +If you want to get the correct `state` after each call to `setState`, you can do it with the following code: + +```js +handle() { + this.setState((prevState) => ({ count: prevState.count + 1 }), () => { + console.log(this.state) + }) +} +``` +# Redux Source Code Analysis + +Let's take a look at the `combineReducers` function first. + +```js +// pass an object +export default function combineReducers(reducers) { + // get this object's keys + const reducerKeys = Object.keys(reducers) + // reducers after filtering + const finalReducers = {} + // get the values corresponding to every key + // in dev environment, check if the value is undefined + // then put function type values into finalReducers + for (let i = 0; i < reducerKeys.length; i++) { + const key = reducerKeys[i] + + if (process.env.NODE_ENV !== 'production') { + if (typeof reducers[key] === 'undefined') { + warning(`No reducer provided for key "${key}"`) + } + } + + if (typeof reducers[key] === 'function') { + finalReducers[key] = reducers[key] + } + } + // get the keys of the reducers after filtering + const finalReducerKeys = Object.keys(finalReducers) + + // in dev environment check and save unexpected key to cache for warnings later + let unexpectedKeyCache + if (process.env.NODE_ENV !== 'production') { + unexpectedKeyCache = {} + } + + let shapeAssertionError + try { + // explanations of the function is below + assertReducerShape(finalReducers) + } catch (e) { + shapeAssertionError = e + } +// combineReducers returns another function, which is reducer after merging +// this function returns the root state +// also notice a closure is used here. The function uses some outside properties + return function combination(state = {}, action) { + if (shapeAssertionError) { + throw shapeAssertionError + } + // explanations of the function is below + if (process.env.NODE_ENV !== 'production') { + const warningMessage = getUnexpectedStateShapeWarningMessage( + state, + finalReducers, + action, + unexpectedKeyCache + ) + if (warningMessage) { + warning(warningMessage) + } + } + // if state changed + let hasChanged = false + // state after changes + const nextState = {} + for (let i = 0; i < finalReducerKeys.length; i++) { + // get the key with index + const key = finalReducerKeys[i] + // get the corresponding reducer function with key + const reducer = finalReducers[key] + // the key in state tree is the same as the key in finalReducers + // so the key of the parameter passed to combineReducers represents each reducer as well as each state + const previousStateForKey = state[key] + // execute reducer function to get the state corresponding to the key + const nextStateForKey = reducer(previousStateForKey, action) + // check the value of state, report error if it's undefined + if (typeof nextStateForKey === 'undefined') { + const errorMessage = getUndefinedStateErrorMessage(key, action) + throw new Error(errorMessage) + } + // put the value into nextState + nextState[key] = nextStateForKey + // if state changed + hasChanged = hasChanged || nextStateForKey !== previousStateForKey + } + // as long as state changed, return the new state + return hasChanged ? nextState : state + } +} +``` + +`combineReducers` is simple in general. In short, it accepts an object and return a function after processing the parameters. This function has an object finalReducers that stores the processed parameters. The object is then itereated on, each reducer function in it is executed, and the new state is returned. + +Let's then take a look at the two functions used in combineReducers. + +```js +// the first function used to throw errors +function assertReducerShape(reducers) { +// iterate on the parameters in combineReducers + Object.keys(reducers).forEach(key => { + const reducer = reducers[key] + // pass an action + const initialState = reducer(undefined, { type: ActionTypes.INIT }) + // throw an error if the state is undefined + if (typeof initialState === 'undefined') { + throw new Error( + `Reducer "${key}" returned undefined during initialization. ` + + `If the state passed to the reducer is undefined, you must ` + + `explicitly return the initial state. The initial state may ` + + `not be undefined. If you don't want to set a value for this reducer, ` + + `you can use null instead of undefined.` + ) + } + // process again, considering the case that the user returned a value for ActionTypes.INIT in the reducer + // pass a random action and check if the value is undefined + const type = + '@@redux/PROBE_UNKNOWN_ACTION_' + + Math.random() + .toString(36) + .substring(7) + .split('') + .join('.') + if (typeof reducer(undefined, { type }) === 'undefined') { + throw new Error( + `Reducer "${key}" returned undefined when probed with a random type. ` + + `Don't try to handle ${ + ActionTypes.INIT + } or other actions in "redux/*" ` + + `namespace. They are considered private. Instead, you must return the ` + + `current state for any unknown actions, unless it is undefined, ` + + `in which case you must return the initial state, regardless of the ` + + `action type. The initial state may not be undefined, but can be null.` + ) + } + }) +} + +function getUnexpectedStateShapeWarningMessage( + inputState, + reducers, + action, + unexpectedKeyCache +) { + // here the reducers is already finalReducers + const reducerKeys = Object.keys(reducers) + const argumentName = + action && action.type === ActionTypes.INIT + ? 'preloadedState argument passed to createStore' + : 'previous state received by the reducer' + + // if finalReducers is empty + if (reducerKeys.length === 0) { + return ( + 'Store does not have a valid reducer. Make sure the argument passed ' + + 'to combineReducers is an object whose values are reducers.' + ) + } + // if the state passed is not an object + if (!isPlainObject(inputState)) { + return ( + `The ${argumentName} has unexpected type of "` + + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + + `". Expected argument to be an object with the following ` + + `keys: "${reducerKeys.join('", "')}"` + ) + } + // compare the keys of the state and of finalReducers and filter out the extra keys + const unexpectedKeys = Object.keys(inputState).filter( + key => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key] + ) + + unexpectedKeys.forEach(key => { + unexpectedKeyCache[key] = true + }) + + if (action && action.type === ActionTypes.REPLACE) return + +// if unexpectedKeys is not empty + if (unexpectedKeys.length > 0) { + return ( + `Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` + + `"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` + + `Expected to find one of the known reducer keys instead: ` + + `"${reducerKeys.join('", "')}". Unexpected keys will be ignored.` + ) + } +} +``` + +Let's then take a look at `compose` function + +```js +// This function is quite elegant. It let us stack several functions via passing the references of functions. The term is called Higher-order function. +// call functions from the right to the left with reduce function +// for the example in the project above +compose( + applyMiddleware(thunkMiddleware), + window.devToolsExtension ? window.devToolsExtension() : f => f +) +// with compose it turns into applyMiddleware(thunkMiddleware)(window.devToolsExtension()()) +// so you should return a function when window.devToolsExtension is not found +export default function compose(...funcs) { + if (funcs.length === 0) { + return arg => arg + } + + if (funcs.length === 1) { + return funcs[0] + } + + return funcs.reduce((a, b) => (...args) => a(b(...args))) +} +``` + +Let's then analyze part of the source code of `createStore` function + +```js +export default function createStore(reducer, preloadedState, enhancer) { + // normally preloadedState is rarely used + // check type, is the second parameter is a function and there is no third parameter, then exchange positions + if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { + enhancer = preloadedState + preloadedState = undefined + } + // check if enhancer is a function + if (typeof enhancer !== 'undefined') { + if (typeof enhancer !== 'function') { + throw new Error('Expected the enhancer to be a function.') + } + // if there is no type error, first execute enhancer, then execute createStore + return enhancer(createStore)(reducer, preloadedState) + } + // check if reducer is a function + if (typeof reducer !== 'function') { + throw new Error('Expected the reducer to be a function.') + } + // current reducer + let currentReducer = reducer + // current state + let currentState = preloadedState + // current listener array + let currentListeners = [] + // this is a very important design. The purpose is that currentListeners array is an invariant when the listeners are iterated every time + // we can consider if only currentListeners exists. If we execute subscribe again in some subscribe execution, or unsubscribe, it would change the length of the currentListeners array, so there might be an index error + let nextListeners = currentListeners + // if reducer is executing + let isDispatching = false + // if currentListeners is the same as nextListeners, assign the value back + function ensureCanMutateNextListeners() { + if (nextListeners === currentListeners) { + nextListeners = currentListeners.slice() + } + } + // ...... +} +``` + +We look at `applyMiddleware` function next + +Before that I need to introduce a concept called function Currying. Currying is a technology for changing a function with multiple parameters to a series of functions with a single parameter. + +```js +function add(a,b) { return a + b } +add(1, 2) => 3 +// for the above function, we can use Currying like so +function add(a) { + return b => { + return a + b + } +} +add(1)(2) => 3 +// you can understand Currying like this: +// we store an outside variable with a closure, and return a function that takes a parameter. In this function, we use the stored variable and return the value. +``` + +```js +// this function should be the most abstruse part of the whole source code +// this function returns a function Curried +// therefore the funciton should be called like so: applyMiddleware(...middlewares)(createStore)(...args) +export default function applyMiddleware(...middlewares) { + return createStore => (...args) => { + // here we execute createStore, and pass the parameters passed lastly to the applyMiddleware function + const store = createStore(...args) + let dispatch = () => { + throw new Error( + `Dispatching while constructing your middleware is not allowed. ` + + `Other middleware would not be applied to this dispatch.` + ) + } + let chain = [] + // every middleware should have these two functions + const middlewareAPI = { + getState: store.getState, + dispatch: (...args) => dispatch(...args) + } + // pass every middleware in middlewares to middlewareAPI + chain = middlewares.map(middleware => middleware(middlewareAPI)) + // same as before, calle very middleWare from right to left, and pass to store.dispatch + dispatch = compose(...chain)(store.dispatch) + // this piece is a little abstract, we'll analyze together with the code of redux-thunk + // createThunkMiddleware returns a 3-level function, the first level accepts a middlewareAPI parameter + // the second level accepts store.dispatch + // the third level accepts parameters in dispatch +{function createThunkMiddleware(extraArgument) { + return ({ dispatch, getState }) => next => action => { + // check if the parameters in dispatch is a function + if (typeof action === 'function') { + // if so, pass those parameters, until action is no longer a function, then execute dispatch({type: 'XXX'}) + return action(dispatch, getState, extraArgument); + } + + return next(action); + }; +} +const thunk = createThunkMiddleware(); + +export default thunk;} +// return the middleware-empowered dispatch and the rest of the properties in store. + return { + ...store, + dispatch + } + } +} +``` + +Now we've passed the hardest part. Let's take a look at some easier pieces. + +```js +// Not much to say here, return the current state, but we can't call this function when reducer is running +function getState() { + if (isDispatching) { + throw new Error( + 'You may not call store.getState() while the reducer is executing. ' + + 'The reducer has already received the state as an argument. ' + + 'Pass it down from the top reducer instead of reading it from the store.' + ) + } + + return currentState +} +// accept a function parameter +function subscribe(listener) { + if (typeof listener !== 'function') { + throw new Error('Expected listener to be a function.') + } + // the major design of this part is already covered in the description of nextListeners. Not much to talk about otherwise + if (isDispatching) { + throw new Error( + 'You may not call store.subscribe() while the reducer is executing. ' + + 'If you would like to be notified after the store has been updated, subscribe from a ' + + 'component and invoke store.getState() in the callback to access the latest state. ' + + 'See http://redux.js.org/docs/api/Store.html#subscribe for more details.' + ) + } + + let isSubscribed = true + + ensureCanMutateNextListeners() + nextListeners.push(listener) + +// return a cancel subscription function + return function unsubscribe() { + if (!isSubscribed) { + return + } + + if (isDispatching) { + throw new Error( + 'You may not unsubscribe from a store listener while the reducer is executing. ' + + 'See http://redux.js.org/docs/api/Store.html#subscribe for more details.' + ) + } + + isSubscribed = false + + ensureCanMutateNextListeners() + const index = nextListeners.indexOf(listener) + nextListeners.splice(index, 1) + } + } + +function dispatch(action) { + // the prototype dispatch will check if action is an object + if (!isPlainObject(action)) { + throw new Error( + 'Actions must be plain objects. ' + + 'Use custom middleware for async actions.' + ) + } + + if (typeof action.type === 'undefined') { + throw new Error( + 'Actions may not have an undefined "type" property. ' + + 'Have you misspelled a constant?' + ) + } + // note that you can't call dispatch function in reducers + // it would cause a stack overflow + if (isDispatching) { + throw new Error('Reducers may not dispatch actions.') + } + // execute the composed function after combineReducers + try { + isDispatching = true + currentState = currentReducer(currentState, action) + } finally { + isDispatching = false + } + // iterate on currentListeners and execute saved functions in the array + const listeners = (currentListeners = nextListeners) + for (let i = 0; i < listeners.length; i++) { + const listener = listeners[i] + listener() + } + + return action + } + // at the end of createStore, invoke an action dispatch({ type: ActionTypes.INIT }); + // to initialize state +``` \ No newline at end of file From 820115765423b21b472b16511b53156de06c36d1 Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 30 Jul 2018 17:31:27 -0300 Subject: [PATCH 2/8] UPGRADE --- Framework/react-br.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index 4dcc4a6d..b9aca33e 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -17,7 +17,7 @@ Nas versões anteriores, se eu tiver um componente composto complexo e então mu ![](https://user-gold-cdn.xitu.io/2018/6/25/164358b0310f476c?w=685&h=739&f=png&s=61462) -If the call stack is too long, and complicated operations are performed in the middle, it may cause the main thread to be blocked for a long time, resulting in a bad user experience. Fiber is born to solve this problem. +Se a pilha de chamada for muito longa, e complicadas operações estiverem no meio, isso pode causar um bloqueio a thread principal por um longe tempo, resultando em uma experiência ruim para o usuário. Fiber nasceu para resolver esse problema. Fiber is essentially a virtual stack frame, and the new scheduler freely schedules these frames according to their priority, thereby changing the previous synchronous rendering to asynchronous rendering, and segmenting the update without affecting the experience. From 11cadb61a0295a2ed222ce8f11dce8f0e329bb25 Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 30 Jul 2018 19:13:18 -0300 Subject: [PATCH 3/8] UPDATE --- Framework/react-br.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index b9aca33e..e968ea51 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -19,28 +19,29 @@ Nas versões anteriores, se eu tiver um componente composto complexo e então mu Se a pilha de chamada for muito longa, e complicadas operações estiverem no meio, isso pode causar um bloqueio a thread principal por um longe tempo, resultando em uma experiência ruim para o usuário. Fiber nasceu para resolver esse problema. -Fiber is essentially a virtual stack frame, and the new scheduler freely schedules these frames according to their priority, thereby changing the previous synchronous rendering to asynchronous rendering, and segmenting the update without affecting the experience. +Fiber é na essência uma pilha virtual de quadros, e o novo agendador espontaneamente agenda esses quadros de acordo +com sua prioridade, desse modo, mudando a renderização síncrona anterior para renderização assíncrona, e segmentando a atualização sem afetar a experiência. ![](https://user-gold-cdn.xitu.io/2018/6/25/164358f89595d56f?w=1119&h=600&f=png&s=330885) -React has its own set of logic on how to prioritize. For things that require high real-time performance, such as animation, which means it must be rendered once within 16 ms to ensure that it is not stuck, React pauses the update every 16 ms (within 16ms) and returns to continue rendering the animation. +React tem seu proprio conjunto de lógica sobre como priorizar. Para coisas que requerem alta performance em tempo-real, tal como animação, que significa isso deve ser renderizado uma vez dentro de 16 ms para garantir que não está emperrando, React pausa o update a cada 16 ms (dentro de 16 ms) e retorna para continuar renderizando a animação. -For asynchronous rendering, there are now two stages of rendering: `reconciliation` and `commit`. The former process can be interrupted, while the latter cannot be suspended, and the interface will be updated until it is completed. +Para renderização assíncrona, existe agora dois estagios de renderização: `reconciliation` e `commit`. O primeiro processo pode ser interrompido, enquanto o último não poder ser suspenso, e a interface será atualizada até isso ser completo. -**Reconciliation** stage +**Reconciliation** etapa - `componentWillMount` - `componentWillReceiveProps` - `shouldComponentUpdate` - `componentWillUpdate` -**Commit** stage +**Commit** etapa - `componentDidMount` - `componentDidUpdate` - `componentWillUnmount` -Because the `reconciliation` phase can be interrupted, the lifecycle functions that will be executed in the `reconciliation` phase may be called multiple times, which may cause bugs. So for these functions, except for `shouldComponentUpdate`, should be avoided as much as possible, and a new API is introduced in V16 to solve this problem. +Pelo fato que a fase de `reconciliation` pode ser interrompida, as funções do ciclo de vida que executaram na fase de `reconciliation` podem ser chamadas multiplas vezes, o que pode causar vários bugs. Então para essas funções, exceto para `shouldComponentUpdate`, devemos evitar assim que possivel, e uma nova API está introduzida na V16 para resolver esse problema. `getDerivedStateFromProps` is used to replace `componentWillReceiveProps` , which is called during initialization and update From f18ada98b82326664346ebb4769fa495004f2a36 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 31 Jul 2018 18:40:46 -0300 Subject: [PATCH 4/8] UPDATE --- Framework/react-br.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index e968ea51..b2f7157d 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -43,12 +43,12 @@ Para renderização assíncrona, existe agora dois estagios de renderização: ` Pelo fato que a fase de `reconciliation` pode ser interrompida, as funções do ciclo de vida que executaram na fase de `reconciliation` podem ser chamadas multiplas vezes, o que pode causar vários bugs. Então para essas funções, exceto para `shouldComponentUpdate`, devemos evitar assim que possivel, e uma nova API está introduzida na V16 para resolver esse problema. -`getDerivedStateFromProps` is used to replace `componentWillReceiveProps` , which is called during initialization and update +`getDerivedStateFromProps` é usado para substituir `componentWillReceiveProps`, do qual é chamado durando a inicialização e atualização ```js class ExampleComponent extends React.Component { - // Initialize state in constructor, - // Or with a property initializer. + // Inicializa o state no construtor, + // Ou com a propriedade initializer. state = {}; static getDerivedStateFromProps(nextProps, prevState) { @@ -59,23 +59,25 @@ class ExampleComponent extends React.Component { }; } - // Return null to indicate no change to state. + // Retorna nulo para indicar que não há mudança no state. return null; } } ``` -`getSnapshotBeforeUpdate` is used to replace `componentWillUpdate`, which is called after the `update` but before the DOM update to read the latest DOM data. +`getSnapshotBeforeUpdate` é usado para substituir o `componentWillUpdate`, do qual é chamado depois do `update` mas antes do DOM atualizar para leitura o último dado do DOM. + +## O conselho usado dos metodos do ciclos de vida no React V16 ## The usage advice of Lifecycle methods in React V16 ```js class ExampleComponent extends React.Component { - // Used to initialize the state + // Usado para iniciar o state constructor() {} - // Used to replace `componentWillReceiveProps` , which will be called when initializing and `update` - // Because the function is static, you can't get `this` - // If need to compare `prevProps`, you need to maintain it separately in `state` + // Usado para substituir o `componentWillReceiveProps`, do qual ira ser chamado quando inicializado e `update` + // Porque a função é estática, você não pode acessar o `this` + // Se você precisar comparar `prevProps`, você precisa manter ele separado no `state` static getDerivedStateFromProps(nextProps, prevState) {} // Determine whether you need to update components, mostly for component performance optimization shouldComponentUpdate(nextProps, nextState) {} From 0721bbe2c44a2b2d8f73e24aa5b5de32a306375f Mon Sep 17 00:00:00 2001 From: Lucas Date: Wed, 1 Aug 2018 10:34:03 -0300 Subject: [PATCH 5/8] UPDATE --- Framework/react-br.md | 68 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index b2f7157d..988484fa 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -67,9 +67,7 @@ class ExampleComponent extends React.Component { `getSnapshotBeforeUpdate` é usado para substituir o `componentWillUpdate`, do qual é chamado depois do `update` mas antes do DOM atualizar para leitura o último dado do DOM. -## O conselho usado dos metodos do ciclos de vida no React V16 - -## The usage advice of Lifecycle methods in React V16 +## O conselho usado nos métodos do ciclo de vida no React V16 ```js class ExampleComponent extends React.Component { @@ -79,23 +77,23 @@ class ExampleComponent extends React.Component { // Porque a função é estática, você não pode acessar o `this` // Se você precisar comparar `prevProps`, você precisa manter ele separado no `state` static getDerivedStateFromProps(nextProps, prevState) {} - // Determine whether you need to update components, mostly for component performance optimization + // Determina se você precisa atualizar os componentes, usado na maioria das vezes para otimização de performance do componente shouldComponentUpdate(nextProps, nextState) {} - // Called after the component is mounted - // Can request or subscribe in this function + // Chamado depois do componente ser montado + // Pode requisitar ou subscrever nessa função componentDidMount() {} - // Used to get the latest DOM data + // Obter o último dado do DOM getSnapshotBeforeUpdate() {} - // Component is about to be destroyed - // Can remove subscriptions, timers, etc. here + // É sobre o componente ser destruido + // Pode remover subscrições, timers, etc. componentWillUnmount() {} - // Called after the component is destroyed + // Chamado depois do componente ser destruido componentDidUnMount() {} - // Called after component update + // Chamado depois da atualização do componente componentDidUpdate() {} - // render component + // renderiza o componente render() {} - // The following functions are not recommended + // As seguintes funções não são recomendadas UNSAFE_componentWillMount() {} UNSAFE_componentWillUpdate(nextProps, nextState) {} UNSAFE_componentWillReceiveProps(nextProps) {} @@ -104,13 +102,13 @@ class ExampleComponent extends React.Component { # setState -`setState` is an API that is often used in React, but it has some problems that can lead to mistakes. The core reason is that the API is asynchronous. +`setState` é uma API que é frequentemente usada no React, mas ele tem alguns problemas que podem levar a erros. O centro das razões é que a API é assíncrona. -First, calling `setState` does not immediately cause a change to `state`, and if you call multiple `setState` at a time, the result may not be as you expect. +Primeiro, chamando `setState` não casa mudança imediata no `state`, e se você chamar multiplos `setState` de uma vez, o resultado pode não ser como o esperado. ```js handle() { - // Initialize `count` to 0 + // Iniciado o `count` em 0 console.log(this.state.count) // -> 0 this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) @@ -119,9 +117,10 @@ handle() { } ``` -First, both prints are 0, because `setState` is an asynchronous API and will only execute after the sync code has finished running. The reason for `setState` is asynchronous is that `setState` may cause repainting of the DOM. If the call is repainted immediately after the call, the call will cause unnecessary performance loss. Designed to be asynchronous, you can put multiple calls into a queue and unify the update process when appropriate. +Primeiro, ambos os prints são 0, porque o `setState` é uma API assíncrona e irá apenas executar depois do código síncrono terminar sua execução. O motivo para o `setState` ser assíncrono é que `setState` pode causar repintar no DOM. Se a chamada repintar imediatamente depois da chamada, a chamada vai causar uma perca de performance desnecessária. Desenhando para ser assíncrono, você pode colocar multiplas chamadas dentro da fila e unificar os processos de atualização quando apropriado. + +Segundo, apesar do `setState` ser chamado três vezes, o valor do `count` ainda é 1. Porque multiplas chamadas são fundidas em uma, o `state` só vai mudar quando a atualização terminar, e três chamadas são equivalente para o seguinte código. -Second, although `setState` is called three times, the value of `count` is still 1. Because multiple calls are merged into one, only `state` will change when the update ends, and three calls are equivalent to the following code. ```js Object.assign( @@ -132,7 +131,7 @@ Object.assign( ) ``` -Of course, you can also call `setState` three times by the following way to make `count` 3 +De fato, você pode também chamar `setState` três vezes da seguinte maneira para fazer `count` 3 ```js handle() { @@ -142,7 +141,8 @@ handle() { } ``` -If you want to get the correct `state` after each call to `setState`, you can do it with the following code: +Se você quer acessar o `state` correto depois de cada chamada ao `setState`, você pode fazer isso com o seguinte código: + ```js handle() { @@ -151,20 +151,20 @@ handle() { }) } ``` -# Redux Source Code Analysis +# Análise de código do Redux -Let's take a look at the `combineReducers` function first. +Vamos dar uma olhada na função `combineReducers` primeiro. ```js -// pass an object +// passe um objeto export default function combineReducers(reducers) { - // get this object's keys + // capture as chaves desse objeto const reducerKeys = Object.keys(reducers) - // reducers after filtering + // reducers depois filtrados const finalReducers = {} - // get the values corresponding to every key - // in dev environment, check if the value is undefined - // then put function type values into finalReducers + // obtenha os valores correspondentes para cada chave + // no ambiente de desenvolvimento, verifique se o valor é undefined + // então coloque os valores do tipo de função dentro do finalReducers for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] @@ -178,10 +178,10 @@ export default function combineReducers(reducers) { finalReducers[key] = reducers[key] } } - // get the keys of the reducers after filtering + // obtenha as chaves dos reducers depois de filtrado const finalReducerKeys = Object.keys(finalReducers) - // in dev environment check and save unexpected key to cache for warnings later + // no ambiente de desenvolvimento verifique e salvo as chaves inesperadas em cache para alertas futuros let unexpectedKeyCache if (process.env.NODE_ENV !== 'production') { unexpectedKeyCache = {} @@ -189,14 +189,14 @@ export default function combineReducers(reducers) { let shapeAssertionError try { - // explanations of the function is below + // explicações de funções estão abaixo assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e } -// combineReducers returns another function, which is reducer after merging -// this function returns the root state -// also notice a closure is used here. The function uses some outside properties +// combineReducers retorna outra função, que é reduzido depois de fundido +// essa função retorna o state raiz +// também percena que um encerramento é usado aqui. A função usa algumas propriedades externas return function combination(state = {}, action) { if (shapeAssertionError) { throw shapeAssertionError From dabb50e4b28593be658376d7eb7e8789d77c0227 Mon Sep 17 00:00:00 2001 From: Lucas Date: Wed, 1 Aug 2018 11:29:36 -0300 Subject: [PATCH 6/8] UPDATE --- Framework/react-br.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index 988484fa..fc200cfb 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -201,7 +201,7 @@ export default function combineReducers(reducers) { if (shapeAssertionError) { throw shapeAssertionError } - // explanations of the function is below + // explicações das funções estão abaixo if (process.env.NODE_ENV !== 'production') { const warningMessage = getUnexpectedStateShapeWarningMessage( state, @@ -215,37 +215,36 @@ export default function combineReducers(reducers) { } // if state changed let hasChanged = false - // state after changes + // state depois das mudanças const nextState = {} for (let i = 0; i < finalReducerKeys.length; i++) { - // get the key with index + // obter a chave com index const key = finalReducerKeys[i] - // get the corresponding reducer function with key + // obter a função de reducer correspondente com a chave const reducer = finalReducers[key] - // the key in state tree is the same as the key in finalReducers - // so the key of the parameter passed to combineReducers represents each reducer as well as each state + // a chave na arvore do state é a mesma chave no finalReducers + // então a chave passada nos parametros para o combineReducers representa cada reducer assim como cada state const previousStateForKey = state[key] - // execute reducer function to get the state corresponding to the key + // execute as funções reducer para pegar o state correspondente a chave const nextStateForKey = reducer(previousStateForKey, action) - // check the value of state, report error if it's undefined + // verifique o valor do state, reporte erros se ele não estiver undefined if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } - // put the value into nextState + // coloque o valor dentro do nextState nextState[key] = nextStateForKey - // if state changed + // se o state mudaou hasChanged = hasChanged || nextStateForKey !== previousStateForKey } - // as long as state changed, return the new state + // enquanto o state mudar, retorne um novo state return hasChanged ? nextState : state } } ``` +`combineReducers` é simples e generico. Resumindo, ele aceita um objeto e retorna uma função depois processado os parâmetros. Essa função tem um objeto finalReducers que armazena os parametros processados. O objeto é então iterado, cada função reducer nela é executada, e o novo state é executado. -`combineReducers` is simple in general. In short, it accepts an object and return a function after processing the parameters. This function has an object finalReducers that stores the processed parameters. The object is then itereated on, each reducer function in it is executed, and the new state is returned. - -Let's then take a look at the two functions used in combineReducers. +Vamos então olhar as duas funções usadas no combineReducers. ```js // the first function used to throw errors From 3bd87951a2b6d1e703cdd35e46cae4e85a8110d1 Mon Sep 17 00:00:00 2001 From: Lucas Date: Thu, 2 Aug 2018 10:10:01 -0300 Subject: [PATCH 7/8] UPDATE --- Framework/react-br.md | 85 ++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index fc200cfb..9714b338 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -247,25 +247,25 @@ export default function combineReducers(reducers) { Vamos então olhar as duas funções usadas no combineReducers. ```js -// the first function used to throw errors +// a primeira função usada para lançar os erros function assertReducerShape(reducers) { -// iterate on the parameters in combineReducers +// iterar nós paramêtros no combineReducers Object.keys(reducers).forEach(key => { const reducer = reducers[key] - // pass an action + // passar uma ação const initialState = reducer(undefined, { type: ActionTypes.INIT }) - // throw an error if the state is undefined + // lança um erro se o state estiver undefined if (typeof initialState === 'undefined') { throw new Error( - `Reducer "${key}" returned undefined during initialization. ` + - `If the state passed to the reducer is undefined, you must ` + - `explicitly return the initial state. The initial state may ` + - `not be undefined. If you don't want to set a value for this reducer, ` + - `you can use null instead of undefined.` + `Reducer "${key}" retorna undefined durante a inicialização. ` + + `Se o state passado para o reducer for undefined, você deve ` + + `explicitamente retornar o state inicial. O state inicial não deve ` + + `ser undefined. Se você não quer definir um valor para esse reducer, ` + + `você pode user null ao invés de undefined.` ) } - // process again, considering the case that the user returned a value for ActionTypes.INIT in the reducer - // pass a random action and check if the value is undefined + // processe novamente, considerando o caso que o usuário retornou um valor para ActionTypes.INIT no reducer + // passa uma ação aleatória e verificar se o valor é undefined const type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random() @@ -275,14 +275,14 @@ function assertReducerShape(reducers) { .join('.') if (typeof reducer(undefined, { type }) === 'undefined') { throw new Error( - `Reducer "${key}" returned undefined when probed with a random type. ` + - `Don't try to handle ${ + `Reducer "${key}" retorna undefined quando sondado com um tipo aleatório. ` + + `Não tente manipular ${ ActionTypes.INIT - } or other actions in "redux/*" ` + - `namespace. They are considered private. Instead, you must return the ` + - `current state for any unknown actions, unless it is undefined, ` + - `in which case you must return the initial state, regardless of the ` + - `action type. The initial state may not be undefined, but can be null.` + } ou outras ações no "redux/*" ` + + `namespace.Eles são considerados privado. Ao invés, você deve retornar o ` + + `state atual para qualquer action desconhecida, a menos que esteja undefined, ` + + `nesse caso você deve retorna o state inicial, independemente do ` + + `tipo da ação. O state inicial não deve ser undefined, mas pode ser null.` ) } }) @@ -294,30 +294,30 @@ function getUnexpectedStateShapeWarningMessage( action, unexpectedKeyCache ) { - // here the reducers is already finalReducers + // aqui os reducers já estão no finalReducers const reducerKeys = Object.keys(reducers) const argumentName = action && action.type === ActionTypes.INIT - ? 'preloadedState argument passed to createStore' - : 'previous state received by the reducer' + ? 'preloadedState argumento passado para o createStore' + : 'state anterior recebido pelo reducer' - // if finalReducers is empty + // se finalReducers estiver vázio if (reducerKeys.length === 0) { return ( - 'Store does not have a valid reducer. Make sure the argument passed ' + - 'to combineReducers is an object whose values are reducers.' + 'Store não tem um reducer válido. Certifique-se de que um argumento foi passado ' + + 'para o combineReducers é um objeto do qual os valores são reducers.' ) } - // if the state passed is not an object + // se o state passado não é um objeto if (!isPlainObject(inputState)) { return ( - `The ${argumentName} has unexpected type of "` + + `O ${argumentName} tem um tipo inesperado de "` + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + - `". Expected argument to be an object with the following ` + - `keys: "${reducerKeys.join('", "')}"` + `". O argumento esperado deve ser um objeto com as seguintes ` + + `chaves: "${reducerKeys.join('", "')}"` ) } - // compare the keys of the state and of finalReducers and filter out the extra keys + // compara as chaves do state a do finalReducers e filtra as chaves extras const unexpectedKeys = Object.keys(inputState).filter( key => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key] ) @@ -328,30 +328,31 @@ function getUnexpectedStateShapeWarningMessage( if (action && action.type === ActionTypes.REPLACE) return -// if unexpectedKeys is not empty +// se unexpectedKeys não estiver vázia if (unexpectedKeys.length > 0) { return ( - `Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` + - `"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` + - `Expected to find one of the known reducer keys instead: ` + - `"${reducerKeys.join('", "')}". Unexpected keys will be ignored.` + `Inesperada ${unexpectedKeys.length > 1 ? 'chaves' : 'chave'} ` + + `"${unexpectedKeys.join('", "')}" encontrada em ${argumentName}. ` + + `Esperado encontrar uma das chaves do reducer conhecida ao invés: ` + + `"${reducerKeys.join('", "')}". Chaves inesperadas serão ignoradas.` ) } } ``` -Let's then take a look at `compose` function +Vamos então dar uma olhada na função `compose` ```js -// This function is quite elegant. It let us stack several functions via passing the references of functions. The term is called Higher-order function. -// call functions from the right to the left with reduce function -// for the example in the project above +// Essa função é bem elegante. Ela nos permite empilhar diversas funções passando a +// referências da função. O termo é chamado de Higher-order function. +// chama funções a partir da direita para esquerda com funções reduce +// por exemplo, no objeto acima compose( applyMiddleware(thunkMiddleware), window.devToolsExtension ? window.devToolsExtension() : f => f -) -// with compose it turns into applyMiddleware(thunkMiddleware)(window.devToolsExtension()()) -// so you should return a function when window.devToolsExtension is not found +) +// Com compose ele retorna dentro do applyMiddleware(thunkMiddleware)(window.devToolsExtension()()) +// então você deveria retorna uma função quando window.devToolsExtension não for encontrada export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg @@ -365,7 +366,7 @@ export default function compose(...funcs) { } ``` -Let's then analyze part of the source code of `createStore` function +Vamos então analisar pare do código da função `createStore` ```js export default function createStore(reducer, preloadedState, enhancer) { From 9de631c35fdf39329e1864a2d3df0461931310e5 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 3 Aug 2018 14:11:51 -0300 Subject: [PATCH 8/8] UPDATE --- Framework/react-br.md | 90 +++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/Framework/react-br.md b/Framework/react-br.md index 9714b338..c5c055fa 100644 --- a/Framework/react-br.md +++ b/Framework/react-br.md @@ -370,36 +370,36 @@ Vamos então analisar pare do código da função `createStore` ```js export default function createStore(reducer, preloadedState, enhancer) { - // normally preloadedState is rarely used - // check type, is the second parameter is a function and there is no third parameter, then exchange positions + // normalmente preloadedState é raramente usado + // verificar o tipo, é o segundo parâmetro da função e não existe terceiro parâmetro, então troque as posições if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } - // check if enhancer is a function + // verifique se enhancer é uma função if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { - throw new Error('Expected the enhancer to be a function.') + throw new Error('É esperado que enhancer seja uma função.') } - // if there is no type error, first execute enhancer, then execute createStore + // se não existe um tipo error, primeiro execute o enhancer, então execute o createStore return enhancer(createStore)(reducer, preloadedState) } - // check if reducer is a function + // verifique se o reducer é uma função if (typeof reducer !== 'function') { - throw new Error('Expected the reducer to be a function.') + throw new Error('É esperado que o reducer seja uma função.') } - // current reducer + // reducer atual let currentReducer = reducer - // current state + // state atual let currentState = preloadedState - // current listener array + // atual listener array let currentListeners = [] - // this is a very important design. The purpose is that currentListeners array is an invariant when the listeners are iterated every time - // we can consider if only currentListeners exists. If we execute subscribe again in some subscribe execution, or unsubscribe, it would change the length of the currentListeners array, so there might be an index error + // esse é um design muito importante. O proposito é que o currentListeners array seja invariante quando os listeners estiverem sendo interado + // Nós podemos considerar se apenas um currentListeners existe. Se nós executarmos o subscribe novamente em alguma execução do subscribe, ou unsubscribe isso mudaria o tamanho do currentListeners array, então devemos ter um index erro let nextListeners = currentListeners - // if reducer is executing + // se o reducer está executando let isDispatching = false - // if currentListeners is the same as nextListeners, assign the value back + // se o currentListeners é o mesmo que o nextListeners, atribua o valor de volta function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() @@ -409,31 +409,31 @@ export default function createStore(reducer, preloadedState, enhancer) { } ``` -We look at `applyMiddleware` function next +Vamos dar uma olhada na função `applyMiddleware` -Before that I need to introduce a concept called function Currying. Currying is a technology for changing a function with multiple parameters to a series of functions with a single parameter. +Antes eu preciso introduzir um conceito chamado Currying. Currying é uma tecnologia para mudar uma função com multiplos parâmetros em uma série de funções com um único parâmetro. ```js function add(a,b) { return a + b } add(1, 2) => 3 -// for the above function, we can use Currying like so +// para a função abaixo, nós usamos Currying igual a function add(a) { return b => { return a + b } } add(1)(2) => 3 -// you can understand Currying like this: -// we store an outside variable with a closure, and return a function that takes a parameter. In this function, we use the stored variable and return the value. +// você pode entender Currying como: +// nós armazenamos uma variável do lado de fora com um closure, e retornamos uma função que leva um parâmetro. Nessa função, nós usamos a variável armazenada e retornamos um valor. ``` ```js -// this function should be the most abstruse part of the whole source code -// this function returns a function Curried -// therefore the funciton should be called like so: applyMiddleware(...middlewares)(createStore)(...args) +// essa função deve ser a parte mais obstrusa de todo código +// essa função retorna um função Curried +// assim sendo a função deve se chamada como: applyMiddleware(...middlewares)(createStore)(...args) export default function applyMiddleware(...middlewares) { return createStore => (...args) => { - // here we execute createStore, and pass the parameters passed lastly to the applyMiddleware function + // aqui nós executamos createStore, e passamos o parâmetro passado por último a função applyMiddleware const store = createStore(...args) let dispatch = () => { throw new Error( @@ -442,24 +442,24 @@ export default function applyMiddleware(...middlewares) { ) } let chain = [] - // every middleware should have these two functions + // todo middleware deve ter essas duas funções const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } - // pass every middleware in middlewares to middlewareAPI + // passar cada middleware nos middlewares para o middlewareAPI chain = middlewares.map(middleware => middleware(middlewareAPI)) - // same as before, calle very middleWare from right to left, and pass to store.dispatch + // assim como antes, chame cada middleware da esquerda para direita, e passo para o store.dispatch dispatch = compose(...chain)(store.dispatch) - // this piece is a little abstract, we'll analyze together with the code of redux-thunk - // createThunkMiddleware returns a 3-level function, the first level accepts a middlewareAPI parameter - // the second level accepts store.dispatch - // the third level accepts parameters in dispatch + // essa parte é um pouco abstrata, nós iremos analisar juntos com o código do redux-thunk + // createThunkMiddleware retorna uma função de 3-nível, o primeiro nível aceita um parâmetro middlewareAPI + // o segundo nível aceita store.dispatch + // o terceiro nível aceita parâmentros no dispatch {function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { - // check if the parameters in dispatch is a function + // verifique se o parâmetro no dispatch é uma função if (typeof action === 'function') { - // if so, pass those parameters, until action is no longer a function, then execute dispatch({type: 'XXX'}) + // se assim for, passe esses parâmetros, até as acões não sejam mais uma função, então execute dispatch({type: 'XXX'}) return action(dispatch, getState, extraArgument); } @@ -469,7 +469,7 @@ export default function applyMiddleware(...middlewares) { const thunk = createThunkMiddleware(); export default thunk;} -// return the middleware-empowered dispatch and the rest of the properties in store. +// retorn o middleware-empowered dispatch e o resto das propriedades no store. return { ...store, dispatch @@ -478,10 +478,10 @@ export default thunk;} } ``` -Now we've passed the hardest part. Let's take a look at some easier pieces. +Agora nós passamos a parte difícil. Vamos olhar uma parte mais fácil. ```js -// Not much to say here, return the current state, but we can't call this function when reducer is running +// Não há muito para dizer aqui, retorne o state atual, mas nós não podemos chamar essa função quando o reducer estiver executando function getState() { if (isDispatching) { throw new Error( @@ -493,12 +493,12 @@ function getState() { return currentState } -// accept a function parameter +// aceita uma função parâmetro function subscribe(listener) { if (typeof listener !== 'function') { throw new Error('Expected listener to be a function.') } - // the major design of this part is already covered in the description of nextListeners. Not much to talk about otherwise + // a maior parte desse design já foi coberto na descrição sobre nextListeners. Não há muito para falar sobre. if (isDispatching) { throw new Error( 'You may not call store.subscribe() while the reducer is executing. ' + @@ -513,7 +513,7 @@ function subscribe(listener) { ensureCanMutateNextListeners() nextListeners.push(listener) -// return a cancel subscription function +// retorne a função de cancelar a subscription return function unsubscribe() { if (!isSubscribed) { return @@ -535,7 +535,7 @@ function subscribe(listener) { } function dispatch(action) { - // the prototype dispatch will check if action is an object + // o prototype dispatch vai verificar se a ação é um objeto if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + @@ -549,19 +549,19 @@ function dispatch(action) { 'Have you misspelled a constant?' ) } - // note that you can't call dispatch function in reducers - // it would cause a stack overflow + // perceba que você não pode chamar uma função dispatch nos reducers + // isso causaria um estouro de pilha if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } - // execute the composed function after combineReducers + // execute a função composta depois do combineReducers try { isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } - // iterate on currentListeners and execute saved functions in the array + // itere nos currentListeners e execute as funções salvas no array de funções const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] @@ -570,6 +570,6 @@ function dispatch(action) { return action } - // at the end of createStore, invoke an action dispatch({ type: ActionTypes.INIT }); - // to initialize state + // no fim do createStore, invoce uma ação dispatch({ type: ActionTypes.INIT }); + // para inicializar o state ``` \ No newline at end of file