Essa é a solução para o desafio [Todo](endereço do desafio). Nesse desafio eu criei um design no figma de um app de todo list para ser desenvolvido com o framework react-native, em que o usuário deve ser capaz de adicionar editar e excluir as suas atividades levando em conta o mais próximo do design possível. .
- Adicionar itens de suas atividades.
- Marcar a atividade como concluida.
- Editar a atividade casa necessário.
- Deletar a atividade caso deseje.
- Persistir os dados.
- React-Native
- Lib Expo linear gradient
- Lib react native async storageExpo
- Semantic HTML5 markup
- Styled-Components
- Redux
Neste projeto, além de colocar em prática os conceitos de React-native tive a oportunidade de usar o styled-component, Async-storage, assim como o redux
1- Usar props atravez do Styled-components
.
export const FinalBar = styled.View`
position: absolute;
bottom: 0;
${props => props.width? (`width:${props.width}px`) : null };
border-radius: 50px;
height: 105px;
touch-action: none;
`
<FinalBar width={width}>
2- Usar a lib expo-linear-gradient
para criar efeitos de gradiente.
import {LinearGradient} from "expo-linear-gradient";
<LinearGradient
style={{flex:1,flexDirection:'row',
justifyContent:"space-between",
alignItems:'center',}}
colors={['#4740534D','#47405300']}
start={{x:0,y:1}}
end={{x:1,y:0}}
>
3- Usar o TouchableOpacity
para poder estilizar o botão.
<TouchableOpacity
activeOpacity={0.5}
onPress={()=> this.onPress()}
>
4- Usar o ScrollView
para que seja possivel fazer o scroll caso os itens ultrapassem a div.
export const ListContainer = styled.ScrollView`
margin-bottom: 40px;
`
<ListContainer>
{todos.map(todo=>(
<TodoListItem
key={todo.id}
todo = {todo}
onPressTodo = {()=> dispatchToggleTodo(todo.id)}
editTodo = {()=> dispatchEditingTodo(todo)}
deleteTodo = {()=> dispatchDeleteTodo(todo)}
/>
))}
</ListContainer>
1- usei o setItem
do AsyncStorage
dentro de um try catch usando o JSON.stringfy
para converter o objeto em json e assim criar ou atualizar os dados
case ADD_TODO:
try {
const newTodo = {
id:nextId,
text: action.text,
done: false,
edit:false
}
AsyncStorageNative.setItem('todos', JSON.stringify([...state, newTodo]))
return[...state, newTodo]
}catch (e){console.log(e)}
2- usei o useEffect com uma função capturando as informações do AsyncStorage
atravez do getItem
para capturar as informaçoes do AsyncStorage
e converti o json em objeto atravez do JSON.stringfy
para poder ser usado no código e passei para o Redux
para assim se existir uma todo gravada ele identificar
e mostrar para o usuario
useEffect( async ()=>{
const totalParse = await AsyncStorageNative.getItem("todos")
const total = JSON.parse(totalParse)
if (total){
dispatchAddTodo(total);
console.log(total)
}
},[])
1- Implementação do Reducer
para poder capturar e manipular atravez das actions
os states
.
⚠️ É importante passar sempre um estado inicial.
import {ADD_TODO, SET_EDITING_TODO, SET_TODO_TEXT, UPDATE_TODO} from "../actions";
const INITIAL_STATE = {
id: null,
text: '',
done:false,
edit:false
};
const editingTodoReducer = (state = INITIAL_STATE ,action)=>{
switch (action.type) {
case SET_TODO_TEXT:
return {
...state,
text:action.text
};
case ADD_TODO:
case UPDATE_TODO:
return INITIAL_STATE
default:
return state;
case SET_EDITING_TODO:
action.todo.edit = true
return action.todo;
}
}
export default editingTodoReducer;
2- Implementação das Actions
que vão ser responsaveis por manipular os states atravez dos reducers.
export const ADD_TODO = 'ADD_TODO';
export const addTodo = text => ({
type: ADD_TODO,
text
});
export const TOGGLE_TODO = 'TOGGLE_TODO';
export const toggleTodo = todoId => ({
type: TOGGLE_TODO,
todoId
})
3- Implementação do combineReducers
para ter um roteamento entre os reducers
de forma individual.
import {combineReducers} from 'redux'
import todoListReducer from "./todoListReducer";
import editingTodoReducer from "./editingTodoReducer";
const rootReducer = combineReducers({
todos: todoListReducer,
editingTodo:editingTodoReducer
});
export default rootReducer;
4- Implementação da Store
onde ficam todas as informações armazenadas, assim como as funções.
import {createStore} from "redux";
import rootReducer from "../reducers";
import {devToolsEnhancer} from "redux-devtools-extension";
export const store = createStore(rootReducer, devToolsEnhancer());
5- Usar o Provider
para ter acesso a os states do Redux.
export default class TodoApp extends Component {
render() {
return (
<Provider store={store} >
<Container>
<Container.Title >To Do List</Container.Title>
<Container.Subtitle >Organize a sua vida</Container.Subtitle>
<TodoForm />
<TodoList />
</Container>
<FinalBar width={width}>
<LinearGradient
style={{flex:1}}
colors={["transparent","rgba(0,0,0,0.83)","#000000"]}
/>
</FinalBar>
</Provider>
6- Usar o mapStateToProps através do connect()
para receber o state.
const mapStateToProps = (state)=>{
return {
todo:state.editingTodo
}
}
export default connect(
mapStateToProps,
{
dispatchAddTodo: addTodo,
})(TodoForm);
7- Usar o dispatch através do connect()
modificar o state.
export default connect(null, {
dispatchAddTodo: addTodo
})(TodoForm);
- Linkdin - Marco Tullio Franca
- Frontend Mentor - @MarcoFranca