update state from another function with useState - javascript

const Room = (props) => {
const [hasError, setErrors] = useState(false);
const [rooms, setRooms] = useState([]);
return (
<div> <a onClick={() => deleteRoom()}</div>
)
}
const deleteRoom = () => {
//How to update setRooms here
}
How do I update setRooms in deleteRoom method?

You simply have to define the deleteRoom function inside the Room component.
const Room = (props) => {
const [hasError, setErrors] = useState(false);
const [rooms, setRooms] = useState([]);
const deleteRoom = () => {
setRooms(...);
}
return (
<div> <a onClick={() => deleteRoom()}</div>
)
}

You can pass setRooms as an argument in deleteRoom and call it there.
For example
const Room = (props) => {
const [hasError, setErrors] = useState(false);
const [rooms, setRooms] = useState([]);
return (
<div> <a onClick={() => deleteRoom(setRooms)}</div>
)
}
const deleteRoom = (setRooms) => {
//How to update setRooms here
setRooms(...)
}

You have 2 options:
Put your deleteRoom method inside the Room component
const Room = (props) => {
const [hasError, setErrors] = useState(false);
const [rooms, setRooms] = useState([]);
const deleteRoom = () => {
... use your state..
}
return (
<div> <a onClick={() => deleteRoom()}</div>
)
}
Pass your useState functions to deleteRoom as arguments.
const Room = (props) => {
const [hasError, setErrors] = useState(false);
const [rooms, setRooms] = useState([]);
return (
<div> <a onClick={() => deleteRoom(setRooms, setErrors)}</div>
)
}
const deleteRoom = (setRooms, setErrors) => {
you can use setRooms() and setErrors() here
}

Related

display Number of page in React Js using material-ui Pagination

look at the code below in my App.js Component:
const App = () => {
const [workstations, setWorkstations] = useState([]);
let [page, setPage] = useState(1);
const PER_PAGE = 1;
useEffect(() => {
loadWorkstations();
}, []);
const loadWorkstations = async () => {
const request = await getWorkstations();
const result = request.data;
setWorkstations(result);
};
const count = Math.ceil(workstations.length / PER_PAGE);
const _DATA = usePagination(workstations, PER_PAGE);
const handleChange = (e, p) => {
setPage(p);
_DATA.jump(p);
};
return (
<Pagination
count={count}
size="large"
page={page}
variant="outlined"
color="primary"
onChange={handleChange}
/>
);
};
now the result that i got form this implementation is like this :
but what im looking for should be look like this :
i mean i don't want to see all my pages on the UI and show the rest with "..."
Note: im using #material-ui/lab
Your code seems alright, however, you need to import Pagination from #mui to achieve the desired behavior
import Pagination from '#mui/material/Pagination';
const App = () => {
const [workstations, setWorkstations] = useState([]);
const [page, setPage] = useState(1);
const [postsPerPage, setPostsPerPage] = useState(10);
const [totalPosts, setTotalPosts] = useState();
const lastPostIndex = page * postsPerPage;
const firstPostIndex = lastPostIndex - postsPerPage;
const currentPosts = workstations.slice(firstPostIndex,lastPostIndex);
useEffect(() => {
loadWorkstations();
}, []);
const loadWorkstations = async () => {
const request = await getWorkstations();
const result = request.data;
setWorkstations(result);
setPage(result.length);
};
return (
<Pagination
count={count}
size="large"
page={page}
variant="outlined"
color="primary"
numberOfPages={totalPages}
totalPosts={currentPosts.length}
postsPerPage={postsPerPage}
setPage={page}
/>
);
};

How do I nest multiple React contexts of the same type

Say I want to create a modal and handle the state through Reacts Context API
export const ModalUIProvider: FC = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const openModal = useCallback(() => setIsOpen(true), [setIsOpen]);
const closeModal = useCallback(() => setIsOpen(false), [setIsOpen]);
const toggleModal = useCallback(
() => setIsOpen(!isOpen),
[isOpen, setIsOpen]
);
const modalContext = useMemo(() => {
return {
isModalOpen: isOpen,
openModal,
closeModal,
toggleModal,
};
}, [isOpen, openModal, closeModal, toggleModal]);
return (
<ModalContext.Provider value={modalContext}>
{children}
</ModalContext.Provider>
);
};
export const useModal = () => {
return useContext<IModalContext>(ModalContext);
};
<ModalUIProvider>
<ParentModal />
</ModalUIProvider>
const { isModalOpen, openModal, closeModal } = useModal();
Now, within this modal I want to have a button, that upon being clicked opens another model ontop of the current one.
How can I do this, without interfering with the wrapping context?

Why do I have undefined in selectedUser?

Why do I have undefined in selectedUser?
After all, I go through the find method through the users array and the first id of the users array should be written to selectedUser
function App() {
const [selectedUserId, setSelectedUserId] = useState(null)
const [users,setUsers] = useState([])
const selectedUser = users.find(u => u.id === selectedUserId)
console.log(users)
console.log(selectedUser)
useAsyncEffect(async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await res.json()
setUsers(data)
}, [])
const onUserClick = (userId) => {
setSelectedUserId(userId)
}
return (
<div>
{ selectedUser ? <ListUsers users={users} onUserClick={onUserClick} /> : <Profile user=
{selectedUser} />
}
</div>
)
}
You can use a loading state to determine when the async function is done and only then you can set the selected user. Otherwise, it remains set to 'null' when the 'return' is rendered.
Below is pseudo code.
function App() {
const [selectedUserId, setSelectedUserId] = useState(null)
const [users,setUsers] = useState([])
const selectedUser = users.find(u => u.id === selectedUserId)
const [loading, setLoading] = useState(false)
console.log(users)
console.log(selectedUser)
useAsyncEffect(async () => {
setLoading(true)
const res = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await res.json()
setUsers(data)
setLoading(false)
}, [])
const onUserClick = (userId) => {
setSelectedUserId(userId)
}
if (loading){
return "Loading..."
// you can use a nicer loader component here
}
return (
<div>
{ selectedUser ? <ListUsers users={users} onUserClick={onUserClick} /> : <Profile user=
{selectedUser} />
}
</div>
)
}

Invalid hook call with nested component call

I have the following code in my App.jsx:
render() {
return (
<BrowserView>
<CreateSession /> // works just fine
<QrCode address={CreateSession(this)} /> // throws 'Error: Invalid hook call.'
</BrowserView>)
}
CreateSession returns a string, which is fed into QrCode, to generate a Qr Code. My CreateSession looks like this:
const CreateSession = (props) => {
const userVideo = useRef();
const partnerVideo = useRef();
const peerRef = useRef();
const socketRef = useRef();
const otherUser = useRef();
const userStream = useRef();
useEffect(() => {
socketRef.current = io.connect("/");
socketRef.current.emit("join session", props.match.params.roomID);
// lots of code omitted, source is: https://github.com/coding-with-chaim/native-webrtc/blob/master/client/src/routes/Room.js
return uuid();
};
export default CreateSession;
What is the correct way to call CreateSession so that it returns the uuid right into QrCode? I am aware that I could have a state property in the App.jsx that gets set to uuid, that is then passed into QrCode, but is it possible to do it this way?
You can turn your CreateSession component into a wrapper.
const CreateSession = (props) => {
const userVideo = useRef();
const partnerVideo = useRef();
const peerRef = useRef();
const socketRef = useRef();
const otherUser = useRef();
const userStream = useRef();
const [uuid, setUuid] = useState(null);
useEffect(() => {
socketRef.current = io.connect("/");
socketRef.current.emit("join session", props.match.params.roomID);
// lots of code omitted, source is: https://github.com/coding-with-chaim/native-webrtc/blob/master/client/src/routes/Room.js
setUuid(uuid());
});
if (uuid === null) {
return null;
}
return (<>{props.children(uuid)}</>)
};
export default CreateSession;
Here is the usage.
render() {
return (
<BrowserView>
<CreateSession>
{(uuid) => (<QrCode address={uuid} />)}
</CreateSession>
</BrowserView>
)
}

How do I use react custom hooks to make code reusable

I have two components similar like below:
const Login = props => {
let loading;
const dispatch = useDispatch();
const [notification, setNotification] = React.useState('');
const [hasNotification, setHasNotification] = React.useState('');
const [isLoading, setIsLoading] = React.useState(false);
const {status, message} = useSelector(state => state.LoginReducer);
const { register, handleSubmit, formState, errors } = useForm({
mode: "onChange"
});
const onSubmit = data => {
setIsLoading(true);
dispatch(loginStart(data));
};
React.useEffect(() => {
setIsLoading(false);
if (status === 422) {
setNotification(message);
setHasNotification('ERROR');
return;
}
if (status === 200) {
setNotification(message);
setHasNotification('SUCCESS');
}
}, [status, message]);
React.useEffect(() => {
console.log('componentDidMount');
return () => {
setNotification('');
setHasNotification('');
};
}, []);
return (
<AuthLayout title={'Login'} header={'Welcome back, Sign in'} hasNotification={hasNotification} notification={notification}>
</AuthLayout>
)
}
export default Login;
I also have another component with similar functionality as above
const Signup = props => {
let loading;
const dispatch = useDispatch();
const [notification, setNotification] = React.useState('');
const [hasNotification, setHasNotification] = React.useState('');
const [isLoading, setIsLoading] = React.useState(false);
const {status, message} = useSelector(state => state.SignupReducer);
const { register, handleSubmit, formState, errors } = useForm({
mode: "onChange"
});
const onSubmit = data => {
setIsLoading(true);
dispatch(signupStart(data));
};
React.useEffect(() => {
setIsLoading(false);
if (status === 422) {
setNotification(message);
setHasNotification('ERROR');
return;
}
if (status === 200) {
setNotification(message);
setHasNotification('SUCCESS');
}
}, [status, message]);
React.useEffect(() => {
console.log('componentDidMount');
return () => {
setNotification('');
setHasNotification('');
};
}, []);
return (
<AuthLayout title={'Signup'} header={'Discover a new way to do amazing work'} hasNotification={hasNotification} notification={notification}>
</AuthLayout>
)
}
export default Signup;
I read about custom hooks but just curious how I can move the state and logic to a separate custom hook function since they have similar structure and functionalities.
What will the custom hook look like?
You can declare all your state/hooks logic in a function and export it to your component:
Example: For your login component you can extract your logic to a file, let's call it useLogin.js
useLogin.js:
export default () => {
const [notification, setNotification] = React.useState('');
const [hasNotification, setHasNotification] = React.useState('');
const [isLoading, setIsLoading] = React.useState(false);
const { register, handleSubmit, formState, errors } = useForm({
mode: "onChange"
});
React.useEffect(() => {
setIsLoading(false);
if (status === 422) {
setNotification(message);
setHasNotification('ERROR');
return;
}
if (status === 200) {
setNotification(message);
setHasNotification('SUCCESS');
}
}, [status, message]);
React.useEffect(() => {
console.log('componentDidMount');
return () => {
setNotification('');
setHasNotification('');
};
}, []);
return [notification, hasNotification, setIsLoading]; //return all variable and functions that you need in your component
}
And in Login you should import your function and use it
import useLogin from './useLogin'; // first import useLogin function
const Login = props => {
let loading;
const dispatch = useDispatch();
const {status, message} = useSelector(state => state.LoginReducer);
const [notification, hasNotification, setIsLoading] = useLogin(); // call useLogin and get notification and hasNotification objects
const onSubmit = data => {
setIsLoading(true);
dispatch(loginStart(data));
};
return (
<AuthLayout title={'Login'} header={'Welcome back, Sign in'} hasNotification={hasNotification} notification={notification}>
</AuthLayout>
)
}
export default Login;
Same thing to Signup component
import useLogin from './useLogin';
const Signup = props => {
let loading;
const dispatch = useDispatch();
const {status, message} = useSelector(state => state.SignupReducer);
const [notification, hasNotification, setIsLoading] = useLogin();
const onSubmit = data => {
setIsLoading(true);
dispatch(signupStart(data));
};
return (
<AuthLayout title={'Signup'} header={'Discover a new way to do amazing work'} hasNotification={hasNotification} notification={notification}>
</AuthLayout>
)
}
export default Signup;
Hope the idea was clear;
You can create a new component with the same code, the difference is in the title and header from AuthLayout
<AuthLayout title={props.title} header={props.header} hasNotification={hasNotification} notification={notification}></AuthLayout>
Login
const Login = props => {
return (
<newComponent title={'Login'} header={'Welcome back, Sign in'} />
)
}
export default Login;
SignUp
const SignUp = props => {
return (
<newComponent title={'SignUp'} header={'Discover a new way to do amazing work'} />
)
}
export default SignUp;
I called newComponent, the component that you will create

Categories