I have a todo list, where I want add some fields:
name
description
I also have two other fields to add:
icon
logo
My image is stored in firebase storage, on this level is worked well. My problem is that when I try to update the card, it only updated the name and description, but the field url remains empty. I am developing on react js and using hooks.
Where do I have an issue? How can I resolve it?
here is an example of my code
const Menu = ({ add, updateCard, contactId }) => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [uploadFile, setUploadFile] = useState(null);
const [url, setImageUrl] = useState('');
const handleChange = useCallback(({ target }) => {
const { name, value } = target;
switch (name) {
case 'name':
setName(value);
break;
case 'description':
setDescription(value);
break;
case 'icon':
setUploadFile(target.files[0]);
break;
case 'logo':
setUploadFile(target.files[0]);
break;
default:
return;
}
}, []);
const resset = () => {
setName('');
setDescription('');
};
const handleSubmit = e => {
e.preventDefault();
resset();
};
useEffect(() => {
if (uploadFile?.name) {
AsynchRoneUploadFile();
}
async function AsynchRoneUploadFile() {
const storageRef = app.storage().ref('Logo');
const fileRef = storageRef.child(uploadFile?.name);
try {
await fileRef.put(uploadFile);
setImageUrl(await fileRef.getDownloadURL());
} catch (e) {
console.log(e.message);
}
}
}, [handleChange, updateCard, uploadFile]);
const buttonName = (add && 'Creat') || (updateCard && 'Update');
return (
<>
<form onSubmit={handleSubmit}>
<Form
handleChange={handleChange}
name={name}
description={description}
/>
<UploadBar onHandlechange={handleChange} />
<button
className={s.btn}
type="submit"
onClick={() =>
(add && add({ name, description, url })) ||
(updateCard &&
updateCard({
contactId,
name,
description,
url,
}))
}
>
{buttonName}
</button>
</form>
</>
);
};
Related
When I delete one of the notes, it deletes from the DB. And to see the effect, I need to reload the page every time I delete a note.
How do I see the not deleted notes without reloading the page?
Here's the code for my page:
export default function Home(notes) {
const [notesData, setNotesData] = useState(notes);
const deleteNote = async (note) => {
const res = await fetch(`http://localhost:3000/api/${note}`, {
method: "DELETE",
});
};
return (
<div>
<h1>Notes:</h1>
{notesData.notes.map((note) => {
return (
<div className="flex">
<p>{note.title}</p>
<p onClick={() => deleteNote(note.title)}>Delete</p>
</div>
);
})}
</div>
);
}
export async function getServerSideProps() {
const res = await fetch(`http://localhost:3000/api`);
const { data } = await res.json();
return { props: { notes: data } };
}
If you're fetching the data with getServerSideProps you need to recall that in order to get the updated data like this :
import { useRouter } from 'next/router';
const router = useRouter()
const refreshData = () => router.replace(router.asPath);
But also you can store the data from getServerSideProps in a state and render that state and trigger a state update after a note is deleted like this :
export default function Home(notes) {
const [notesData, setNotesData] = useState(notes);
const deleteNote = async (note) => {
const res = await fetch(`http://localhost:3000/api/${note}`, {
method: "DELETE",
});
};
return (
<div>
<h1>Notes:</h1>
{notesData.notes.map((note) => {
return (
<div className="flex">
<p>{note.title}</p>
<p onClick={() => deleteNote(note.title).then(()=>{
const res = await fetch(`http://localhost:3000/api`);
const { data } = await res.json();
setNotesData(data)
})
}>Delete</p>
</div>
);
})}
</div>
);
}
export async function getServerSideProps() {
const res = await fetch(`http://localhost:3000/api`);
const { data } = await res.json();
return { props: { notes: data } };
}
I am using react redux-thunk. I have a set of users data that I get from an API and this is the schema:
.
I've connected the "active" property with the checked attribute of a Switch MUI button, so naturally when calling the API I have some users with their switch button already on "true". What I am trying to do is to just make the switch functional, and just be able to click it and change its state, not necessarily doing anything with that.
Here's my toggleType.js:
export const TOGGLE = "TOGGLE";
Here's my toggleAction.js:
import { TOGGLE } from "./toggleType";
const statusToggleAction = () => {
return {
type: TOGGLE,
};
};
export const statusToggle = () => {
return (dispatch) => {
dispatch(statusToggleAction);
};
};
Here's my toggleReducer.js:
import { TOGGLE } from "./toggleType";
const initialState = {
status: false,
};
const toggleReducer = (state = initialState, action) => {
switch (action.type) {
case TOGGLE:
status: true;
default:
return state;
}
};
export default toggleReducer;
Everything is under my userContainer.js, like that:
function UserContainer({ userData, fetchUsers }) {
useEffect(() => {
fetchUsers();
}, []);
return userData.loading ? (
<h2>Loading</h2>
) : userData.error ? (
<h2>{userData.error}</h2>
) : (
<Container maxWidth="lg" style={{ flexGrow: 1, height: "100%" }}>
<h2>User List</h2>
<div>
{userData &&
userData.users &&
userData.users.map((user) => (
<div key={user.id}>
<p>{user.name}</p>
<Switch checked={user.active} onChange={statusToggle()} />
</div>
))}
</div>
</Container>
);
}
const mapStateToProps = (state) => {
return { userData: state.user, statusToggle: state.status };
};
const mapDispatchToProps = (dispatch) => {
return {
fetchUsers: () => dispatch(fetchUsers()),
statusToggle: () => dispatch(statusToggle()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserContainer);
This is the error I am getting whenever I am clicking one of those switches:
Any ideas are welcome, I "learned" redux like 3 days ago!
toggleReducer function in toggleReducer.js, replace status: true; with return { status: true }.
Just return action in statusToggle function in toggleAction.js without dispatch as following.
export const statusToggle = () => {
return statusToggleAction();
};
Or just call statusToggleAction directly in userContainer.js as following.
export const statusToggle = () => {
return (dispatch) => {
dispatch(statusToggleAction());
};
};
Whenever I check for the existence of the condition isAuthorized (true or false) I get this error message on the console. Basically the error refers to server-side rendering, but I can't identify where I should fix it. When i remove isAuthorized the error disappears.
I have my context, I return isAuthorized as true or false depending on the existence of the token in the cookie.
GlobalContext.js
const Global = createContext();
export function GlobalContextProvider({ children }) {
const { push } = useRouter();
const userCookie = Cookies.getJSON("user");
const [authUser, setAuthUser] = useState(() => {
if (userCookie) return userCookie;
if (!userCookie) return {};
});
const [isAuthorized, setIsAuthorized] = useState(() => {
return !authUser || Object.keys(authUser).length == 0 ? false : true;
});
useEffect(() => {
if (!isAuthorized) {
return push("/auth/login");
}
}, [isAuthorized]);
const value = {
isAuthorized,
setIsAuthorized,
authUser,
setAuthUser,
};
return <Global.Provider value={value}>{children}</Global.Provider>;
}
export const useGlobalContext = () => useContext(Global);
Index.jsx
export default function PanelLayout({ children, title }) {
const { push } = useRouter();
const { isAuthorized, setIsAuthorized } = useGlobalContext();
useEffect(() => {
const userData = Cookies.getJSON("user");
if (!userData || !userData.access_token) {
return push("/auth/login");
setIsAuthorized(false);
}
}, []);
return (
<>
{isAuthorized && (
<>
<Head>
// Content
</Head>
<input type="checkbox" id="sidebar-toggle" />
<div className="main-content">
// Content
</div>
</>
)}
</>
);
}
use this code in routes file where all the routes with components are placed.
and place this useEffect there if this condition meets give the access to that routes otherwise redirect it to login.
useEffect(() => {
const userData = Cookies.getJSON("user");
if (!userData || !userData.access_token) {
return push("/auth/login");
setIsAuthorized(false);
}
}, []);
I am implementing Oauth from google with redux, and I wanted to have all google API calls handled from my redux and ended up writing helper functions in my actions file that doesn't return anything or call dispatch. I ended up with code where I only dispatch once from my JSX file and wondering if this is okay or there is another better way to do it?
The code is as follows:
authActions.js
const clientId = process.env.REACT_APP_GOOGLE_OAUTH_KEY;
let auth;
export const authInit = () => (dispatch) => {
window.gapi.load('client:auth2', () =>
window.gapi.client.init({ clientId, scope: 'email' }).then(() => {
auth = window.gapi.auth2.getAuthInstance();
dispatch(changeSignedIn(auth.isSignedIn.get()));
auth.isSignedIn.listen((signedIn) => dispatch(changeSignedIn(signedIn)));
})
);
};
export const signIn = () => {
auth.signIn();
};
export const signOut = () => {
auth.signOut();
};
export const changeSignedIn = (signedIn) => {
const userId = signedIn ? auth.currentUser.get().getId() : null;
return {
type: SIGN_CHANGE,
payload: { signedIn, userId },
};
};
GoogleAuth.jsx
import { useSelector, useDispatch } from 'react-redux';
import classNames from 'classnames';
import { authInit, signIn, signOut } from '../../actions/authActions';
function GoogleAuth() {
const { signedIn } = useSelector((state) => state.auth);
const dispatch = useDispatch();
useEffect(() => {
dispatch(authInit());
}, [dispatch]);
const onClick = () => {
if (signedIn) {
signOut();
} else {
signIn();
}
};
let content;
if (signedIn === null) {
return null;
} else if (signedIn) {
content = 'Sign Out';
} else {
content = 'Sign In';
}
return (
<div className="item">
<button
className={classNames('ui google button', {
green: !signedIn,
red: signedIn,
})}
onClick={onClick}
>
<i className="ui icon google" />
{content}
</button>
</div>
);
}
export default GoogleAuth;
The code works fine, but it feels like it might be misleading having action calls in JSX but not dispatching it, is it okay?
I'm following egghead.io Redux course by Dan.
However I've no idea why my todo app is not working. It doesn't output any error and any warning, just doesn't work.
Can you please give me some hint.
This is my jsbin.
https://jsbin.com/cozecip/33/edit?js,output
const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
id: state.id,
text: state.text,
completed: !state.completed
};
default:
return state;
}
};
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
];
case 'TOGGLE_TODO':
return state.map(t =>
todo(t, action)
);
default:
return state;
}
};
const visibilityFilter = (state = 'SHOW_ALL', action) =>
{
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
};
const { combineReducers } = Redux;
const todoApp = combineReducers({
todos,
visibilityFilter
});
const { createStore } = Redux;
const store = createStore(todoApp);
const { Component } = React;
const FilterLink = ({
filter,
currentFilter,
children,
onClick
}) => {
if (filter === currentFilter){
return <span>{children}</span>
}
return (
<a href="#" onClick ={onClick}>{children}</a>
);
};
const Todo = ({
onClick,
completed,
text
}) => (
<li
onClick={onClick}
style={{
textDecoration:
completed ?
'line-through' :
'none'
}}
>
{text}
</li>
);
const TodoList = ({
todos,
onTodoClick
}) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
const AddTodo = ({
onAddClick
}) => {
let input;
return (
<div>
<input ref={node => {
input = node;
}} />
<button onClick={() => {
onAddClick(input.value)
input.value = '';
}}>
Add Todo
</button>
</div>
);
}
const Footer = ({
visibilityFilter,
onFilterClick
}) => (
<p>
Show:
{' '}
<FilterLink
filter='SHOW_ALL'
currentFilter={visibilityFilter}
onClick={onFilterClick}>
All
</FilterLink>
{' '}
<FilterLink
filter='SHOW_ACTIVE'
currentFilter={visibilityFilter}
onClick={onFilterClick}>
Active
</FilterLink>
{' '}
<FilterLink
filter='SHOW_COMPLETED'
currentFilter={visibilityFilter}
onClick={onFilterClick}>
Completed
</FilterLink>
</p>
)
const getVisibleTodos = (todos, filter) => {
switch(filter){
case 'SHOW_ALL':
return todos;
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed);
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed);
default:
return todos;
}
}
let nextTodoId = 0;
const TodoApp = ({
todos,
visibilityFilter
}) => {
return (
<div>
<AddTodo
onAddClick={
text =>
store.dispatch({
type: 'ADD_TODO',
text: this.input.value,
id: nextTodoId++
})
}
/>
<TodoList
todos={
getVisibleTodos(
todos,
visibilityFilter
)
}
onTodoClick={id =>
store.dispatch({
type: 'TOGGLE_TODO',
id
})
}
/>
<Footer
visibilityFilter={visibilityFilter}
onFilterClick={filter =>
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter
})
}
/>
</div>
);
}
const render = () => {
ReactDOM.render(
// Render the TodoApp Component to the <div> with id 'root'
<TodoApp
{...store.getState()}
/>,
document.getElementById('root')
);
};
store.subscribe(render);
render();
Make sure you have added the correct ID in index.js
it should look like this.
document.getElementById('your div id from index.html should go here')