You are viewing the Portuguese (Brazil) site, but your language preference is set to English. Switch to English site →

Menu

Como usar Redux com Flex

Em grande parte do seu desenvolvimento com o Flex UI (IU do Flex), o estado do componente pode ser informado por dados que já estão no Flex; por exemplo, você pode obter acesso à tarefa atual e renderizar os dados da tarefa em seu componente personalizado.

No entanto, existem algumas instâncias em que adicionar informações a uma tarefa pode comprometer a segurança ou até mesmo apenas incluir dados desnecessários à própria tarefa. Nesses casos, você pode estender o armazenamento Redux do seu Flex UI (IU do Flex) e passar as novas informações de assinatura para seus componentes personalizados.

Nesta página, abordaremos duas estratégias para modificar o redutor Redux do Flex. A primeira estratégia conta com o Plugin Builder para estender seu contact center hospedado no flex.twilio.com. A segunda estratégia envolve modificar diretamente a maneira como o Flex constrói o Redux e é ideal se você planeja hospedar o Flex na sua própria infraestrutura.

Breve introdução ao Redux

Redux é um pacote de software que ajuda os desenvolvedores a gerenciar o estado do aplicativo. O Flex usa o Redux para gerenciar vários estados do aplicativo; por exemplo, uma nova tarefa que aparece na IU ou um agente que muda de Available para Busy são exemplos de alteração do estado do aplicativo. O Redux oferece alguns recursos interessantes:

  • uma única fonte de verdade sobre o estado do seu aplicativo (chamada de loja)
  • uma interface para enviar ações que atualizarão a loja
  • uma arquitetura que facilita o teste e a depuração de alterações de estado e, talvez o mais importante,
  • uma integração com React que permite que os componentes React assinem as alterações na loja.

Confira a documentação do Redux para saber mais sobre todos os excelentes recursos que ele oferece e se tornar um mestre do Redux. Você também pode obter uma visão geral útil do Redux no Code Cartoon Introdução ao Redux.

Como usar o Redux em seu plugin do Flex

Ao usar o Plugin Builder do Flex, você já estará usando o Redux! O código do plugin padrão inclui todos os bits e partes de que você precisa para gerenciar o estado da IU do plugin. Você pode aprender tudo sobre como criar seu primeiro plugin aqui.

Depois de configurar o plugin, você pode encontrar a maior parte do código do padrão Redux em src/states/CustomTaskListState.js. Para facilitar a leitura desta página, o conteúdo dos arquivos do criador de plugins está localizado nos exemplos de código nesta página; portanto, não se preocupe se você ainda não conseguir configurar seu primeiro plugin.

        
        
        

        CustomTaskListState.js

        Definir uma ação

        Vamos começar com a ação que causará alguma alteração no estado da IU. No plugin de amostra, ela é chamada de ACTION_DISMISS_BAR, e como você pode imaginar, ela dispensa uma barra na parte superior da interface do usuário.

        Você notará que há muitos lugares que dizem ACTION_DISMISS_BAR no código.

        const ACTION_DISMISS_BAR = 'DISMISS_BAR';

        No exemplo de código de plugin, criamos uma variável chamada ACTION_DISMISS_BAR, atribuímos a ela uma string com o conteúdo 'DISMISS_BAR'.

        Assim que o Flex UI (IU do Flex) estiver em execução, as ações começarão a acontecer por todo o lugar. O Redux precisa de um identificador exclusivo para entender o que são todas essas ações e o que elas devem fazer para o estado do aplicativo. Portanto, todas as ações enviadas precisam de um nome, e o Redux procurará o conjunto de instruções sobre como ele deve mudar de estado para ações com esse nome específico. Para não confundir o Redux, a melhor prática é usar variáveis, que garantem que o identificador permaneça consistente em todos os lugares em que você estiver usando a ação.

        Você precisará do ID da ação quando estiver escrevendo o redutor, os componentes e os testes. O uso de uma variável para o nome permite renomear a ação REMOVE_BAR alterando‐a em um único local. Você pode se sentir confiante de que seu código será executado corretamente em toda a base de código (e ficará bem no Redux DevTools, mas essa é uma história para outro momento!)

        Gravar o redutor

        O redutor é definido com a seguinte função:

        export function reduce(state = initialState, action) {...}

        Essa função retorna uma versão atualizada do aplicativo com base na ação enviada.

        Então, qual é o estado do aplicativo?

        const initialState = {
          isOpen: true,
        };

        Este objeto Javascript reflete uma pequena parte do estado do aplicativo. O trabalho do redutor é aplicar a ação ao objeto de estado atual para criar uma versão atualizada do estado. Em seguida, ele retornará o estado atualizado para o Redux. O Redux combinará posteriormente este redutor com um grupo de outros redutores para criar um grande armazenamento do estado do seu aplicativo.

        Observe que o redutor returns uma nova cópia do estado sempre que processa uma ação. Se você apenas modificar o estado sem retorná‐lo, o estado do aplicativo não será atualizado corretamente. Saiba mais sobre esses tipos de padrões no Guia de estilo do Redux.

        Um redutor geralmente é uma instrução switch longa, com os vários cases sendo seus diferentes nomes de ação. Nesse caso (ah! Viu o que fizemos lá?), o redutor lida com dois casos: se vir uma ação com o identificador ACTION_DISMISS_BAR, ele altera o valor isOpen para false. Caso contrário, se ele não reconhecer o identificador da ação (ou não houver um), ele apenas manterá o estado atual do aplicativo.

        Adicionar o estado do plugin ao armazenamento Flex

        Agora que você tem esse objeto de estado, precisará disponibilizá‐lo para o Flex. Isso ocorre em src/YourPluginName.js com o método addReducer. Esse é um método que o Flex fornece para incluir seu redutor na loja do Flex, então esse é o código Flex, não o Redux. Ele disponibiliza o estado do redutor e a lógica associada no Flex UI (IU do Flex).

              
              
              

              YourPluginName.js

              Acessar o Redux a partir do componente do plugin

              Agora que a lógica do redutor está definida, você precisa conectar toda essa lógica à IU. No app de exemplo do Plugin Builder, isso ocorre em src/components/CustomTaskList/CustomTaskList.Container.js.

                    
                    
                    
                    Lógica do componente do contêiner

                    CustomTaskList.Container.js

                    Lógica do componente do contêiner

                    No React, é comum criar um componente de contêiner que contenha a lógica para buscar dados para o componente e um componente de apresentação que manipule a lógica para renderizar o próprio componente. Não se prenda muito a esse padrão, mas há muitos recursos disponíveis se você tiver curiosidade de saber mais sobre por que o exemplo do plugin está estruturado dessa maneira!

                    O código aqui contém algumas partes principais da lógica:

                    // Import redux methods
                    import { connect } from 'react-redux';
                    import { bindActionCreators } from 'redux';
                    
                    // Import the Redux Actions
                    import { Actions } from '../../states/CustomTaskListState';
                    import CustomTaskList from './CustomTaskList';

                    Primeiro, ele importa tudo de que precisa dos pacotes NodeJS e os arquivos Action/Component no app React

                    const mapStateToProps = (state) => ({
                        isOpen: state['sample'].customTaskList.isOpen,
                    });
                    
                    const mapDispatchToProps = (dispatch) => ({
                      // Note: the plugin's sample code uses a function called bindActionCreators here
                      // For the sake of clarity, we're using the dispatch function directly here
                      dismissBar: dispatch(Actions.dismissBar),
                    });

                    Duas funções, mapStateToProps e mapDispatchToProps, são definidas. Todos os componentes do React têm propriedades, ou props, que você pode usar para alterar como o componente é exibido. Como o nome indica, mapStateToProps descreve quais "fragmentos" específicos do estado do aplicativo que o componente deve conhecer. Nesse caso, ele está definindo o valor de isOpen.

                    mapDispatchToProps descreve as ações que o componente pode enviar para o Redux. Nesse caso, a proposta do componente dismissBar deve ter uma função que possa enviar a ação DISMISS_BAR.

                    export default connect(mapStateToProps, mapDispatchToProps)(CustomTaskList);

                    Por fim, você verá um método connect sofisticado. Ele associa essas funções de mapeamento ao componente React de apresentação. Os componentes de apresentação props agora terão valores definidos por essas funções.

                    Você pode ver a magia acontecer no próprio código do componente.

                          
                          
                          

                          CustomTaskList.jsx

                          A proposta do componente isOpen também tem um valor definido, graças à função mapStateToProps.

                          const CustomTaskList = (props) => {
                            if (!props.isOpen) {
                              return null;
                            }

                          Aqui, ele está sendo usado para renderizar condicionalmente o componente HTML.

                          O componente está invocando a proposta dismissBar.

                          <i className="accented" onClick={props.dismissBar}>
                          

                          Essa proposta foi definida com mapDispatchToProps e permite que o componente envie a ação DISMISS_BAR sempre que um usuário clicar no texto close.

                          O Redux ajuda você a criar um fluxo de dados por meio de todo o plugin. O usuário interage com o componente, que chama a função dispatch. A função dispatch envia a ação relevante ao redutor. O redutor pega qualquer informação associada a essa ação (nesse caso, alternando isOpen) e modifica o armazenamento do Redux para refletir o que está acontecendo. Finalmente, o componente, que está inscrito na loja, é atualizado usando o poder do React, refletindo o novo estado do aplicativo!

                          O Redux tem um fluxo de dados complexo, mas depois de dominá‐lo, ele faz com que o raciocínio e o teste de aplicativos complexos, como a IU para um Contact Center omnichannel, seja muito mais fácil.

                          Adding State to the Redux Store

                          You can add additional state to your Plugin's component. Inside src/states/CustomTaskListState.js, define your state in the initialState object, as well as a variable that will represent the state's action.

                          const ACTION_DISMISS_BAR = 'DISMISS_BAR';
                          const ACTION_UPDATE_MESSAGE = 'UPDATE_MESSAGE';
                          
                          const initialState = {
                            isOpen: true,
                            message: 'Flex is Awesome!',
                          }

                          Define an Action that will tell Redux how to update your component's state.

                          export class Actions {
                            static dismissBar = () => ({ type: ACTION_DISMISS_BAR });
                            static updateMessage = (value) => ({ type: ACTION_UPDATE_MESSAGE, value });
                          }

                          When your component updates the state, it will dispatch an action which will call the reducer in order to update the state.

                          export function reduce(state = initialState, action) {
                            switch (action.type) {
                              case ACTION_DISMISS_BAR: {
                                return {
                                  ...state,
                                  isOpen: false,
                                };
                              }
                              case ACTION_UPDATE_MESSAGE: {
                                return {
                                  ...state,
                                  message: action.value, // update the message state property with new value stored in action object.
                                };
                              }
                              default:
                                return state;
                            }
                          }

                          Now that you have added a new state value to the initialState object, defined a Redux Action, and handled the ACTION_UPDATE_MESSAGE action by implementing a case inside the reducer function, you need to map the state properties and dispatch functions to your components props. Doing this will allow you to retrieve the data from the Redux Store, as well as update the state of the Redux Store with new values.

                          Inside src/CustomTaskList/CustomTaskList.Container.js, modify the mapStateToProps method:

                          // Import redux methods
                          import { connect } from 'react-redux';
                          import { bindActionCreators } from 'redux';
                          
                          // Import the Redux Actions
                          import { Actions } from '../../states/CustomTaskListState';
                          import CustomTaskList from './CustomTaskList';
                          
                          // Define mapping functions
                          const mapStateToProps = (state) => ({
                              isOpen: state['sample'].customTaskList.isOpen,
                              message: state['sample'].customTaskList.message, // maps the message state property to component's props
                          });
                          
                          const mapDispatchToProps = (dispatch) => ({
                            dismissBar: bindActionCreators(Actions.dismissBar, dispatch),
                            updateMessage: bindActionCreators(Actions.updateMessage, dispatch), // maps the updateMessage function to the component's props
                          });
                          
                          // Connect presentational component to Redux
                          export default connect(mapStateToProps, mapDispatchToProps)(CustomTaskList);
                          

                          Finally, inside src/CustomTaskList/CustomTaskList.jsx, you can reference message and alertMessage as component props.

                          import React from 'react';
                          
                          import { CustomTaskListComponentStyles } from './CustomTaskList.Styles';
                          
                          // It is recommended to keep components stateless and use redux for managing states
                          const CustomTaskList = (props) => {
                            if (!props.isOpen) {
                              return null;
                            }
                          
                            return (
                              <CustomTaskListComponentStyles>
                                This is a dismissible demo component
                                <i className="accented" onClick={props.dismissBar}>
                                  close
                                </i>
                                <span>{props.message}</span>
                                {/* when you type something it will update the message state property */}
                                <input type="text" value={props.message} onChange={(e) => props.updateMessage(e.target.value) } />
                              </CustomTaskListComponentStyles>
                            );
                          };
                          
                          export default CustomTaskList;

                          Gravar ações assíncronas

                          O Flex UI (IU do Flex) usa o middleware redux-promise para processar ações assíncronas.

                                
                                
                                

                                AsyncExample.js

                                Há alguns termos principais a serem indicados aqui:

                                Ações assíncronas referem‐se a qualquer código de ação que não retorna dados imediatamente. Por exemplo, nesse código, escrevemos uma função que, em sua descrição mais simples, retorna uma foto de um cão. Associamos essa função a uma ação, com a ideia de que poderíamos, por exemplo, fazer com que um cliente clique em um botão para ver uma foto de um cachorrinho fofo.

                                // Fetches a picture of a dog
                                function getDogPhoto() {
                                    return fetch('https://dog.ceo/api/breeds/image/random')
                                        .then((response) => response.json())
                                        .catch((err) => {
                                            return `Error: ${err}`;
                                        });
                                }
                                
                                export const Actions = {
                                // Invoke the getDogPhoto
                                    samplePromise: () => ({
                                        type: 'GET_DOG_PHOTO',
                                        payload: getDogPhoto(),
                                    })
                                };

                                Por padrão, o Redux lançaria um erro com esse código! Isso ocorre porque nossa primeira função não retorna uma foto de cachorro, ela retorna a Promessa de uma foto de cachorro. O Redux precisa de um objeto para retornar ao redutor, não a Promessa de um objeto!

                                Se você precisar melhorar seu entendimento das promessas, confira o documento API Promise do Mozilla para saber mais.

                                As promessas podem ser resolvidas de várias maneiras diferentes e, portanto, precisamos ensinar ao Redux que ele deve estar esperando promessas e, em seguida, para cada Promessa em nosso código, precisamos definir como lidar com os vários resultados da Promessa. Digite: our Middleware.

                                O middleware redux-promise nos permite escrever um redutor parecido com este:

                                export function reduce(state = initialState, action) {
                                  switch (action.type) {
                                    // Action for Redux-Promise-Middleware Pending State
                                    case `${ACTION_GET_DOG_PHOTO}_PENDING`:
                                      return state;
                                    // Action for Redux-Promise-Middleware Success State
                                    case `${ACTION_GET_DOG_PHOTO}_FULFILLED`:
                                      return {
                                        ...state,
                                        image: action.payload.message,
                                      };
                                    // Action for Redux-Promise-Middleware Failed State
                                    case `${ACTION_GET_DOG_PHOTO}_REJECTED`:
                                      return {
                                        ...state,
                                        error: action.payload.error,
                                      };
                                    default:
                                      return state;
                                  }
                                }

                                Em vez de apenas uma ação GET_DOG_PHOTO, o redutor lida com três ações que lidam com cada estado de promessa. O middleware pode lançar uma ação pendente (que é útil para renderizar os controles giratórios de carregamento e informar às pessoas que algo está acontecendo), uma ação cumprida se tudo funcionar corretamente (aqui, usamos isso para adicionar a imagem do cão à nossa loja Redux) e uma ação com falha (no caso de algo dar errado, como a API de fotos de cachorro estar inativa e precisarmos mostrar um erro.)

                                Como esse middleware já está integrado ao redutor da Flex IU (IU do Flex), você notará que não há necessidade de escrever, por conta própria, código adicional para importar o middleware ou definir a lógica de controle de promessas. Você pode começar a escrever código assíncrono sempre que estiver pronto!

                                Combinar o redutor do seu aplicativo e o redutor da Flex IU (IU do Flex)

                                Se você criou seu próprio aplicativo Redux, pode estender sua própria IU para incluir todos os benefícios com informações de estado no Flex. Essa opção só é recomendada se você já tiver um app React existente; caso contrário, os plugins provavelmente serão uma opção melhor. A amostra de código a seguir é um breve exemplo de como você pode integrar o Flex ao seu próprio aplicativo.

                                import Flex from "@twilio/flex-ui"
                                import myReducer from './myReducerLocation'
                                
                                // Use Redux's combineReducers method to add your reducer to the Flex reducer
                                const reducers = combineReducers({
                                    flex: Flex.FlexReducer,
                                    app: myReducer
                                });
                                
                                const middleware = applyMiddleware();
                                
                                // Redux builts a store using the reducers and applies Flex middleware
                                const store = createStore(
                                    reducers,
                                    compose(
                                        middleware,
                                        Flex.applyFlexMiddleware()
                                    )
                                );
                                
                                // Flex is instantiated with the new store, which includes your custom reducer
                                Flex
                                    .Manager.create(configuration, store)
                                    .then(manager => {     
                                        ReactDOM.render(
                                            <Provider store={store}>
                                                <Flex.ContextProvider manager={manager}>
                                                    <Flex.RootContainer />
                                                </Flex.ContextProvider>
                                            </Provider>,
                                            container
                                        );
                                    })
                                

                                O que vem a seguir?

                                Classifique esta página:

                                Precisa de ajuda?

                                Às vezes, todos nós precisamos; a programação é difícil. Receba ajuda agora da nossa equipe de suporte, ou confie na sabedoria da multidão navegando pelo Stack Overflow Collective da Twilio ou buscando a tag Twilio no Stack Overflow.

                                Obrigado pelo seu feedback!

                                Selecione o(s) motivo(s) para seu feedback. As informações adicionais que você fornece nos ajudam a melhorar nossa documentação:

                                Enviando seu feedback...
                                🎉 Obrigado pelo seu feedback!
                                Algo deu errado. Tente novamente.

                                Obrigado pelo seu feedback!

                                thanks-feedback-gif