Aprenda através um exemplo simples como usar o Redux no React JS e deixar sua aplicação mais flexível e adaptada para evoluções futuras e mais complexas
Para exemplificar o uso do REDUX em uma aplicação REACT JS, faremos uso de um cadastro simples de nomes de tarefas, onde o usuário irá incluir o nome de uma tarefa em uma lista.
Na aplicação, teremos um formulário que receberá um nome de uma tarefa e acionará uma ACTION para adicionar o nome e ativar o REDUCER para alterar, a partir do STORE, o estado da lista de nomes já incluídos. Com o estado evoluído, o componente irá renderizar na VIEW a lista de nomes.
Partimos do pressuposto que já se tenha o ambiente de desenvolvimento em React configurado, inclusive com a ferramenta create-react-app.
O código fonte da aplicação está no github.
Torne-se um programador Full Stack Javascript Profissional
RELACIONADO – Como entender React e como funciona o React JS?
Criar a aplicação
create-react-app react-cadastro-tarefas-redux
Remover arquivos
Depois de criada a aplicação, excluir os seguintes arquivos:
– App.css
– App.js
– App.test.js
– index.css
– logo.svg
Criar a estrutura de pastas da aplicação
Dentro da pasta src criar as seguintes pastas:
– src/components/
– src/components/todo/
– src/components/main/
– src/actions/
– src/reducers/
– src/store/
Ajustar estrutura inicial do projeto
Como realizamos diversas exclusões, vamos ajustá-la para poder compilar normalmente.
Vamos criar o componente App.jsx dentro da pasta src/components/main/ com o seguinte conteúdo:
import React from 'react';
function App() {
return (
<div>
<h1>Cadastro de tarefas</h1>
</div>
);
}
export default App;
Em seguida ajustar o arquivo index.js com o seguinte conteúdo:
import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import App from './components/main/App';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
Depois disso, executar dentro da pasta raiz do projeto, o comando npm start e verificar se compilou e exibiu o nome Cadastro de tarefas no browser.
Adicionar as bibliotecas do redux e do react-redux
npm install redux react-redux
Criar um arquivo de constantes de Actions
Criar um arquivo de contantes relativo às ações que poderão ser realizadas no componente de tarefas, o actionTypes.js dentro de src/actions/ com o seguinte conteúdo:
export const ADD_TODO = ‘ADD_TODO’;
Criar o Reducer relativo ao estado do componente de tarefas.
Dentro da pasta reducers, criar um arquivo todoReducer.js (src/reducers/todoReducer.js) com o seguinte conteúdo:
import {ADD_TODO} from ‘../actions/actionTypes’;
const initialState ={
todos :[],
showTodos: false
}
export const TodoReducer = (state= initialState, action) =>{
switch (action.type){
case ADD_TODO:
return {
…state,
todos: state.todos.concat(action.payload),
showTodos: true
}
default:
return state;
}
}
Criar o reducer raiz
Embora nossa aplicação seja pequena, é uma boa prática criar um reducer que junte todos os outros que existirem na aplicação.
Dentro da pasta reducers, criar um arquivo rootReducer.js (src/reducers/rootReducer.js) com o seguinte conteúdo:
import {combineReducers} from ‘redux’;
import {TodoReducer} from ‘./todoReducer’
export const RootReducer = combineReducers({todoAction: TodoReducer});
Criar a action para inclusão de uma nova tarefa
Dentro da pasta actions criar o arquivo todoAction.js (src/actions/todoAction.js) com o seguinte conteúdo:
import {ADD_TODO} from ‘./actionTypes’;
export const addTodo = todoName => ({
type: ADD_TODO,
payload: todoName
})
Criar o store
Dentro da pasta store, criar o arquivo store.js (src/store/store.js) com o seguinte conteúdo:
import {createStore} from ‘redux’;
import {RootReducer} from ‘../reducers/rootReducer’;
export const Store = createStore(RootReducer);
Incluir o provider do store
No arquivo index.js, deveremos incluir o provider com o store da aplicação. O arquivo index.js ficará com o seguinte conteúdo:
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import {Provider} from ‘react-redux’;
import * as serviceWorker from ‘./serviceWorker’;
import App from ‘./components/main/App’;
import {Store} from ‘./store/store’;
ReactDOM.render(
<Provider store={Store}>
<App />
</Provider>
, document.getElementById(‘root’));
serviceWorker.unregister();
Criar componentes Todo
O cadastro de tarefas serão representados por 4 componentes:
1 Componente de c lasse
todo.jsx
3 Componentes funcionais
todoForm.jsx
todoItem.jsx
todoList.jsx
Todos eles ficarão na pasta src/components/todo
1. Arquivo todoItem.jsx
import React from ‘react’;
const TodoItem = (props) =>{
return (
<div>
{props.todoName}
<br/>
<br/>
</div>
);
}
export default TodoItem;
2. Arquivo todoList.jsx
import React from ‘react’;
import {connect} from ‘react-redux’;
import TodoItem from ‘./todoItem’;
const TodoList = (props) =>{
return (
<div>
{ props.todos.map(todo =>
<TodoItem key={todo} todoName ={todo}/>
)
}
</div>
);
}
const mapsStateToProps = state => ({
todos: state.todoAction.todos,
showTodos:state.todoAction.showTodos
})
export default connect(mapsStateToProps)(TodoList);
3. Arquivo todoForm.jsx
import React from ‘react’;
const TodoForm = (props) => {
return (
<div>
<form onSubmit={props.submitHandler}>
<input type=”text” name=”valueName” onChange={props.changeHandler} value={props.valueName}/>
<br/>
<br/>
<input type=”submit” value=”Add”/>
</form>
</div>
)
}
export default TodoForm;
4. Arquivo todo.jsx
import React, { Component } from ‘react’;
import {connect} from ‘react-redux’;
import {bindActionCreators} from ‘redux’;
import TodoForm from ‘./todoForm’;
import TodoList from ‘./todoList’;
import {addTodo} from ‘../../actions/todoAction’;
class Todo extends Component {
state = {
valueName: ”
}
constructor(props) {
super(props);
this.changeHandler = this.changeHandler.bind(this);
this.submitHandler = this.submitHandler.bind(this);
}
submitHandler = event => {
if(this.state.valueName !== ”){
this.props.addTodo(this.state.valueName);
this.setState({
valueName:”
})
event.preventDefault();
}
}
changeHandler = event => {
this.setState({
valueName:event.target.value
})
}
render() {
return (
<div>
<TodoForm valueName={this.state.valueName} submitHandler={this.submitHandler} changeHandler={this.changeHandler} />
<br />
<TodoList />
</div>
)
}
}
const mapDispatchToProps = dispatch => bindActionCreators({addTodo},dispatch);
export default connect(null,mapDispatchToProps)(Todo);
Ajuste no arquivo App.jsx
import React from ‘react’;
import Todo from ‘../todo/todo’
function App() {
return (
<div>
<h1>Cadastro de tarefas</h1>
<Todo/>
</div>
);
}
export default App;
Explicando a aplicação
A aplicação é um cadastro simples de nomes de tarefas feito em react utilizando o redux como gerenciador de estados.
No reducer temos o estado inicial das tarefas. Temos assim dois atributos :
1. A lista de tarefas, representada pelo array todos: []
2. Um atributo booleano para informar se a lista deverá ser exibida ou não, representado por showTodos: true. Ele poderá ser usado em evoluções futuras do projeto.
O componente de classe todo.jsx tem dois componentes funcionais:
1. todoForm.jsx: tem o objetivo de capturar o nome da tarefa e repassar ao componente Todo
2. todoList.jsx: tem o objetivo de renderizar a lista de tarefas. Dentro desse arquivo, tem um componente todoItem, que exibirá o conteúdo de cada linha da lista.
No componente Todo, temos que disparar o evento que irá acionar o reducer para evoluir o estado e adicionar a tarefa à lista.
Isso é feito a partir da conexão do mapDispatchToProps:
const mapDispatchToProps = dispatch => bindActionCreators({addTodo},dispatch);
export default connect(null,mapDispatchToProps)(Todo);
Já no componente TodoList, temos que associar a lista do reducer para exibição em tela. Isso é feito a partir do mapStateToProps:
const mapsStateToProps = state => ({
todos: state.todoAction.todos,
showTodos:state.todoAction.showTodos
})
export default connect(mapsStateToProps)(TodoList);
Para testar a aplicação, basta executar o comando npm start ou yarn start.