how can i multiple context state handle in screen? - reactjs

how can i multiple context state handle in screen?                               
const { state } = useContext(profileContext);
const { state,AttendanceInGetByDate } = useContext(AttendanceContax);

You can rename properties while destructuring:
const { state: profileDAta } = useContext(profileContext);
const { state: attendanceData, AttendanceInGetByDate } = useContext(AttendanceContax);
There are a lot of articles on destructuring in Javascript, it's kind of hype recently(one of them), choose any.
Moreover you don't have to use destructuring with hooks if that creates any inconvenience to you:
const profile = useContext(profileContext);
const attendance = useContext(AttendanceContax);
...
// here you can refer to profile.state and attendance.state independently

Related

react.js useState hook is assigned a value but not used, but that is ok

I have this setup so that the render is forces when they click by simply updating the state of a hook. Is there a nicer or cleaner way to do this.. here is some code...
const [click, setClick] = useState();
function handle1Click() {
props.UserInfoObject.setWhichPlot(1)
setClick(1000 * 60 * 5)
}
return (
<div>
<button onClick={handle1Click}>5 Minutes</button>
</div>
I came accross this which is another option but I am trying to be as optimal as possible so I am unsure which to use, or if there is another method?
handleClick = () => {
// force a re-render
this.forceUpdate();
};
I only mention this because of the warning that pops up stating this "'click' is assigned a value but never used no-unused-vars
***EDIT
adding the UserInfoObject class for reference
class UserInformation {
constructor(airValue, waterValue){
this.airValue = airValue;
this.waterValue = waterValue;
this.getCalibrationsFlag = false;
this.numberDevices = 0;
this.deviceName = 'defaultName';
this.currentlyChangingName = false;
this.whichPlot = 1;
}
setAirValue(number) {
this.airValue = number;
}
setWaterValue(number) {
this.waterValue = number;
}
setNumberDevices(int){
this.numberDevices = int;
}
setDeviceName(name){
this.deviceName = name;
}
setCurrentlyChangingName(boolean){
this.currentlyChangingName = boolean;
}
setWhichPlot(number){
this.whichPlot = number;
}
}
let UserInfoObject = new UserInformation(10000, -10);
With React, you should generally use pure, functional programming when possible. Mutating objects makes it much, much harder to do things properly.
Create state of the UserInformation instead. When it needs to be changed, instead of mutating the existing object, create a new object. The fact that this object is new will tell React that the component needs to re-render.
const [userInformation, setUserInformation] = useState({
airValue, // this should be in the outer scope
waterValue, // this should be in the outer scope
getCalibrationsFlag: false,
numberDevices: 0,
// ...
});
Do that in the parent component, then pass both userInformation and setUserInformation down as props. In the child, handle1Click can then be changed to:
const handle1Click = () => setUserInformation({
...userInformation,
whichPlot: 1,
});
Neither state nor props should ever be mutated in React.

Implementing undo/redo function in react

I am trying to implement simple undo/redo function in my react app. So I am trying to maintain an array with old state values. But when I check the values of the old states, its all updated with the new state.
state :
state = {
schedule : [],
loads:[],
undo:[],
redo:[]
};
const redoUndoObj ={
oldStateSchedule : [...this.state.schedule],
oldStateLoads : [...this.state.loads]
}
this.setState({ undo : [ ...this.state.undo , redoUndoObj]});
I hope this give you an idea on how to solve the problem. I made code only for undo now to point you in the right direction. This example I made via React functional component using useState instead of Component class.
const [schedule, setSchedule] = useState([]);
const [loads, setLoads] = useState([]);
const [undo, setUndo] = useState([]);
const [redo, setRedo] = useState([]);
const updateData = (newSchedule, newLoads) => {
setSchedule([...newSchedule]);
setLoads([...newLoads]);
const newUndo = {
schedule: [...newSchedule],
loads: [...newLoads],
};
setUndo([...undo, ...newUndo]);
}
const undoChanges = () => {
const lastElement = undo[undo.length - 1];
const copyOfUndo = [...undo];
// Update redo to be able to rollback
setRedo([...undo]);
// Set the previous values to Schedule and Loads
schedule([...lastElement.schedule]);
loads([...lastElement.loads]);
// Remove the last element from undo
lastElement.pop();
undo([...lastElement]);
}

Should I use useMemo in hooks?

I created useBanner hooks
const useBanner = (array, yardage) => {
const [bannArr, setBannArr] = useState(array.slice(0, yardage));
const [bannListIndex, setBannIndex] = useState(1);
return {
....
};
};
Am I doing the right thing and the props throw in useState.
It’s permissible to use useBanner.
const Banner= ({
array,
yardage
}) => {
const { bannForth, bannBeck, bannArr } = useBanner(array, yardage);
return (
...
);
};
when props will change here.
Will change the state in useBanner.
or is it considered anti-patterns I have to write all this in useMemo
const useBanner = (array, yardage) => {
const [bannArr, setBannArr] = useState([]);
const [bannListIndex, setBannIndex] = useState(1);
useMemo(() => {
setBannArr(array.slice(0, yardage));
setBannIndex(1);
}, [array, yardage]);
return {
....
};
};
Yes, custom hooks are possible in React. Here is separate document discussing custom hooks.
But exactly you sample may require additional code depending on what is your final goal.
If you want initialize state only once, when component Banner is first created, you can just do as in your first sample
const Banner= ({
array,
yardage
}) => {
const { bannForth, bannBeck, bannArr } = useBanner(array, yardage);
return (
...
);
};
This will work perfectly. But if props array and yardage will change, this will not be reflected in component. So props will be used only once as initial values and then will not be used in useBanner even if changed (And it doesn't matter whether you'll use useBanner or useState directly). This answer highlight this.
If you want to update inital values on each props change, you can go with useEffect like below
const Banner= ({
array,
yardage
}) => {
const { bannForth, bannBeck, bannArr, setBannArr } = useBanner(array, yardage);
useEffect (() => {
// setBannArr should also be returned from useBanner. Or bannArr should be changed with any other suitable function returned from useBanner.
setBannArr(array.slice(0, yardage));
}, [array, yardage, setBannArr])
return (
...
);
};
In this case Banner component can control state itself and when parent component change props, state in Banner component will be reset to new props.
Here is small sample to showcase second option.

Central State Management without Redux or Mobx?

Recently I contemplated the idea of having central state management in my React apps without using Redux or Mobx, instead opting to create something similar to the application class in Android. In any event, I implemented something similar to this:
Create a store folder and a file called store.js in it whose contents are:
// State
let state = {
users: {},
value: 0
};
// Stores references to component functions
let triggers = [];
// Subscription Methods
export const subscribe = trigger => {
triggers.push(trigger);
trigger();
}
export const unsubscribe = trigger => {
let pos = -1;
for (let i in triggers) {
if (triggers[i]===trigger) {
pos = i;
break;
}
}
if (pos!==-1) {
triggers.splice(pos, 1);
}
}
// Trigger Methods
let triggerAll = () => {
for (let trigger of triggers) {
trigger();
}
}
// State Interaction Methods
export const setUser = (name, description) => {
state.users[name] = description;
triggerAll();
}
export const removeUser = name => {
if (name in state.users) {
delete state.users[name];
}
triggerAll();
}
export const getAllUsers = () => {
return state.users;
}
export const getUser = name => {
if (!(name in state.users)) {
return null;
}
return state.users[name];
}
export const getValue = () => {
return state.value;
}
export const setValue = value => {
state.value = value;
triggerAll();
}
And connecting to this store in the following manner:
// External Modules
import React, { Component } from 'react';
import {Box, Text, Heading} from 'grommet';
// Store
import {subscribe, unsubscribe, getAllUsers} from '../../store/store';
class Users extends Component {
state = {
users: []
}
componentDidMount() {
subscribe(this.trigger); // push the trigger when the component mounts
}
componentWillUnmount() {
unsubscribe(this.trigger); // remove the trigger when the component is about to unmount
}
// function that gets triggered whenever state in store.js changes
trigger = () => {
let Users = getAllUsers();
let users = [];
for (let user in Users) {
users.push({
name: user,
description: Users[user]
});
}
this.setState({users});
}
render() {
return <Box align="center">
{this.state.users.map(user => {
return <Box
style={{cursor: "pointer"}}
width="500px"
background={{color: "#EBE7F3"}}
key={user.name}
round
pad="medium"
margin="medium"
onClick={() => this.props.history.push("/users/" + user.name)}>
<Heading margin={{top: "xsmall", left: "xsmall", right: "xsmall", bottom: "xsmall"}}>{user.name}</Heading>
<Text>{user.description}</Text>
</Box>
})}
</Box>;
}
}
export default Users;
Note. I've tested this pattern on a website and it works. Check it out here. And I apologize I am trying to keep the question concise for stackoverflow, I've provided a more detailed explanation of the pattern's implementation here
But anyway, my main question, what could be the possible reasons not to use this, since I assume if it was this simple, people wouldn't be using Redux or Mobx. Thanks in advance.
That's what Redux and MobX basically do, you are wrong in thinking that at their core concept they are much different. Their size and complexity came as a result of their effort to neutralize bugs and adapt to a vast variety of application cases. That's it. Although they might be approaching the task from different angles, but the central concept is just that. Maybe you should familiarize your self with what they actually do underneath.
Btw, you do not need to store redundant state in your component, if all you need is to trigger the update. You can just call forceUpdate() directly:
// function that gets triggered whenever state in store.js changes
trigger = () => {
this.forceUpdate();
}
That's similar to what Redux and MobX bindings for react do under the hood.

React & Reselect selector claims state is the same after update

I am implementing Reselect in my project and have a little confusion on how to properly use it. After following multiple tutorials and articles about how to use reselect, I have used same patterns and still somethings dont work as expected.
My selector:
const getBaseInfo = (state) => state.Info;
const getResources = (state) => state.Resources;
export const ASelector = createSelector(
[getBaseInfo, getResources],
(items, resources) => {
let result = {};
for(const item in items) {
console.log(item);
result[item] = _.pick(items[item], ['Title', 'Type', 'Beginning', 'minAmount', 'Address'])
}
for(const item in resources) {
console.log(item);
result[item] = {...result[item], firstImage: resources[item].firstImage}
}
return result;
}
);
mapStateToProps component:
function mapStateToProps(state) {
console.log(state);
return {
gridInfo: ASelector(state)
}
}
Now at first my initial state is:
state = { Info: {}, Resources: {} }
My Reducer:
const Info = ArrayToDictionary.Info(action.payload.data.Info);
const Resources = ArrayToDictionary.Resources(action.payload.data.Info);
let resourcesKeys = Object.keys(Resources);
let infoKeys = Object.keys(Info);
let temp = { ...state };
let newInfo;
for (let item of infoKeys) {
newInfo = {
Title: Info[item].Title,
Type: Info[item].Type,
BeginningOfInvesting: Info[item].BeginningOfInvesting,
DateOfEstablishment: Info[item].DateOfEstablishment,
pricePerUnit: Info[item].PricePerUnit,
minUnits: Info[item].MinUnits,
publicAmount: Info[item].PublicAmount,
minInvestmentAmount: Info[item].MinInvestmentAmount,
EinNumber: Info[item].EinNumber,
Address: Info[item].Address,
Status: Info[item].Status,
Lat: Info[item].Lat,
Lng: Info[item].Lng,
CurrencySymbol: Info[item].CurrencySymbol,
Publicity: Info[item].Publicity
}
temp.Info[item] = { ...temp.Info[item], ...newInfo }
}
for (let item of resourcesKeys) {
temp.Resources[item] = { ...temp.Resources[item], ...Resources[item] }
}
return temp;
As a component renders with the initial state, I have an action pulling data from api and saving it accordingly into the state inside reducers.
Now my state is changed, but after debugging a little into reselects code, I found in the comparison function that the old and new states are the same.
Suddenly my "old" state became already populated with the newState data and it of course failing the comparison as they became the same.
Is there anything wrong with my selectors?
I have really tried to use it as the documentation states, but still cant understand how to solve my little issue.
Thank you very much for reading and helping!
It looks like the temp.Info[item] and temp.Resources[item] lines are mutating the existing state. You've made a shallow copy of the top level, but aren't correctly copying the second level. See the Immutable Update Patterns page in the Redux docs for an explanation of why this is an issue and what to do instead.
You might want to try using the immer library to simplify your immutable update logic. Also, our new redux-starter-kit library uses Immer internally.

Resources