I have a component count. It changes. I add dynamically function component as many as count.
Then I want to get values of variables.
const MainComponent: React.FC<Props> = ({ fields, label, addCount }) => {
const components = () => {
const comps = [];
for (let index = 0; index < addCount; index++) {
comps.push(<CampaignConfigurationProperty fields={fields[index]} label={label}></CampaignConfigurationProperty>);
}
return comps;
};
return (
<div>
<p>{label}</p>
<div className={styles.anotherText + " " + styles.endText + " col"}>
{components()}
</div>
</div>
);
};
export default MainComponent;
this is code i think have error but this is help you !
const MainComponent: React.FC<Props> = ({ fields, label, addCount }) => {
const [comps , setComps] = useState<any>([])
useEffect(() => {
const components = () => {
const x = []
for (let index = 0; index < addCount; index++) {
x.push({fild: fields[index]} ,label :label );
}
return comps;
};
setComps(components())
},[])
return (
<div>
<p>{label}</p>
<div className={styles.anotherText + " " + styles.endText + " col"}>
{comps.map((i , index) =>
<CampaignConfigurationProperty key={index} fields={i.fild} label={i.label} />
)}
</div>
</div>
);
};
export default MainComponent;
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>
</>
);
};
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);
}
}, []);
thanks for reading my post.
It's hard to describe my issue.
I have a reactive object cached globally(like a store and let's call it 'store' here) to preserve the states together with some actions. It's working all good initially. But when I added more pages & switching between the pages, the components are broken after re-rendering. The components can still read correctly from the store and call the actions to update the store data and can console.log the 'fingerprint' to show it's the same store. But the updated data in store is no longer updated in the UI. I can console.log the data in store which looks all good, but the UI is frozen with the data since last unmounted.
I'm providing my component code below.
<template>
<div class="min-w-full relative" ref="container">
<hi-transition slow>
<center-box
v-if="loading"
class="absolute w-full h-full left-0 top-0 text-primary-light opacity-50"
>
<hi-spinner class="w-1/6 h-1/6" :stroke="2" />LOADING...
</center-box>
<div v-else-if="noResult">
No Result
</div>
<hi-markable
v-else
class="w-full h-full divide-y divide-primary-lighter overflow-y-auto block"
:search="searchValue"
>
<div
v-for="item in displayItems"
:key="item.id"
class="hover:bg-primary-lightest transition-colors duration-500 flex items-center block"
#click="selectItem(item)"
:style="{
'min-height': minItemHeight + 'px',
height: itemHeight + 'px'
}"
:class="{ active: currentItem === item }"
>
<slot :item="item" />
</div>
</hi-markable>
</hi-transition>
</div>
</template>
<script>
import { inject, ref } from "vue";
import HiSpinner from "#/ui/HiSpinner";
import CenterBox from "#/ui/elements/CenterBox";
import HiTransition from "#/ui/HiTransition";
import HiMarkable from "#/ui/HiMarkable";
import { computed } from "vue";
export default {
name: "HiDataList",
components: { HiMarkable, HiTransition, CenterBox, HiSpinner },
props: {
storeToken: String,
minItemHeight: [Number, String],
autoItemsPerPage: Boolean
},
emits: ["select"],
setup(props, { emit }) {
//this store is a reactive object cached somewhere
const store = inject(props.storeToken);
//to make sure it's the same store
console.log("fingerprint", store.fingerprint);
const { displayItems, currentItem, loading, searchValue, noResult } = store;
const container = ref(null);
const itemHeight = computed(() => {
return props.autoItemsPerPage
? store.autoItemHeight.value
: props.minItemHeight;
});
if (props.autoItemsPerPage) {
store.autoItemsPerPage(container, props.minItemHeight);
}
function selectItem(item) {
console.log(item);
emit("select", item);
store.setCurrentItem(item);
}
return {
displayItems,
selectItem,
container,
itemHeight,
currentItem,
loading,
searchValue,
noResult
};
}
};
</script>
<style scoped>
.active,
.active:hover {
#apply bg-primary-lighter border-primary-light;
}
</style>
The listStore
import { computed, reactive, watch, toRefs } from "vue";
import { useElementSize } from "#vueuse/core";
import { watchProps } from "#/utils/reactiveHelpers";
function filter(item, filters) {
const f = (key, filter) => {
const itemVal = item[key];
if (Array.isArray(itemVal)) return itemVal.indexOf(filter) >= 0;
else return itemVal === filter;
};
for (let key in filters) {
const filterVal = filters[key];
if (Array.isArray(filterVal)) {
for (let i = 0; i < filterVal.length; i++) {
if (f(key, filterVal[i])) return true;
}
} else {
return f(key, filterVal);
}
}
return false;
}
const getTime = date => {
if (date.milliseconds) return date.milliseconds;
if (date.seconds) return date.seconds;
if (date.getTime) return date.getTime();
};
const createListStore = (source, settings = {}) => {
const state = reactive({
source: source,
currentPage: 0,
itemsPerPage: 0, //zero means display all
loading: true,
ready: false,
noData: false,
noResult: false,
filters: {},
search: null,
searchables: settings.searchables || [],
sortBy: null,
sortType: "alpha",
desc: false,
currentItem: null,
autoItemHeight: 0,
fingerprint: Math.random() * 10000000000000000
});
// const { itemsPerPage,source,filters,search,searchables,sortBy,sortType,desc } = toRefs(state);
const {
itemsPerPage,
ready,
loading,
noResult,
search,
autoItemHeight
} = toRefs(state);
watchProps(state, "source", v => {
if (typeof v !== "undefined") {
state.ready = true;
state.loading = false;
if (!v.length) state.noData = true;
}
});
const currentPage = computed(() => state.currentPage + 1);
// const itemsPerPage = computed(() => state.itemsPerPage);
const totalItems = computed(() => results.asc.length);
const from = computed(() => {
if (totalItems.value === 0) return 0;
return state.currentPage * state.itemsPerPage + 1;
});
const to = computed(() => {
const t = from.value + displayItems.value.length - 1;
return t > totalItems.value ? totalItems.value : t;
});
const totalPages = computed(() => {
if (totalItems.value === 0 || state.itemsPerPage === 0) return 1;
return Math.ceil(totalItems.value / state.itemsPerPage);
});
const gotoPage = page => {
console.log("gotoPage", page);
state.currentPage = page - 1;
console.log(state.currentPage);
};
const prevPage = () => {
if (state.currentPage > 0) state.currentPage--;
};
const nextPage = () => {
if (state.currentPage < totalPages.value) state.currentPage++;
};
const updateFilters = (filter, val) => {
state.filters[filter] = val;
};
/**
*
* #param column
* #param desc
* #param type "alpha"|"number"|"date"|"time"
*/
const sortBy = (column, desc = false, type = "alpha") => {
state.sortBy = column;
state.desc = desc;
state.sortType = type;
};
function doSearch(item) {
const searchables = state.searchables;
for (let i = 0; i < searchables.length; i++) {
const key = searchables[i];
let value = item[key];
if (value && typeof value === "string") {
value = value.toLowerCase();
}
if (value && value.indexOf(state.search) >= 0) {
return true;
}
}
return false;
}
const results = reactive({
desc: [],
asc: []
});
function calcResults() {
if (!state.ready || state.noData) return null;
// console.log("re-calc results....");
const hasFilters = Object.keys(state.filters).length > 0;
// console.log(Object.keys(state.filters));
let items = [];
if (hasFilters || (state.search && state.search.length)) {
//do filter & search
const source = state.source;
for (let i = 0; i < source.length; i++) {
const item = source[i];
// console.log(filter(item, state.filters));
if (hasFilters && !filter(item, state.filters)) {
continue;
}
if (state.search && state.search.length && !doSearch(item)) {
continue;
}
items.push(item);
}
if (!items.length) {
results.desc = results.asc = [];
return null;
}
} else {
items = state.source;
}
if (state.sortBy) {
//do sort
const sort = state.sortBy;
// const desc = state.desc ? -1 : 1;
const type = state.sortType.toLowerCase();
items.sort((a, b) => {
a = a[sort];
b = b[sort];
if (type === "date" || type === "time") {
return getTime(a) - getTime(b);
} else {
if (typeof a === "string") a = a.trim();
if (typeof b === "string") b = b.trim();
if (state.sortType.toLowerCase() === "number") {
return a - b;
} else {
return a.localeCompare(b, "en", { sensitivity: "base" });
}
}
});
}
results.asc = items;
results.desc = [...items].reverse();
// return items;
}
//changed to watch for the wired vue error.
watchProps(
state,
["source", "filters", "search", "searchables", "sortBy", "sortType"],
() => {
calcResults();
state.noResult = results.asc.length === 0;
}
);
const displayItems = computed(() => {
if (!results.asc.length) return [];
const re = state.desc ? results.desc : results.asc;
if (state.itemsPerPage === 0) return re;
const from = state.currentPage * state.itemsPerPage;
const to = from + state.itemsPerPage;
return re.slice(from, to);
});
/**
*
* #param elementRef ref
* #param minHeight Number
* #param itemHeightRef ref
*/
const autoItemsPerPage = (elementRef, minHeight) => {
const { height } = useElementSize(elementRef);
// console.log(elementRef);
watch(height, v => {
const items = Math.floor(v / minHeight);
// itemHeightRef.value = v / items;
// console.log(v / items);
state.itemsPerPage = items;
state.autoItemHeight = v / items;
});
};
const setCurrentItem = item => {
console.log("set current", state.fingerprint);
state.currentItem = item;
};
const currentItem = computed(() => state.currentItem);
return {
currentPage,
itemsPerPage,
totalItems,
displayItems,
from,
to,
totalPages,
gotoPage,
prevPage,
nextPage,
ready,
loading,
updateFilters,
sortBy,
search: v => (state.search = v),
searchValue: search,
autoItemsPerPage,
setCurrentItem,
currentItem,
noResult,
autoItemHeight,
fingerprint: state.fingerprint
};
};
export { createListStore };
The store provider
import { provide } from "vue";
import { createListStore } from "#/ui/storeProvider/listStore";
const storeDepot = {};
export const provideListStore = (token, source, settings = {}) => {
if (!storeDepot[token]) {
console.log("create new store", token);
storeDepot[token] = createListStore(source, settings);
}
provide(token, storeDepot[token]);
return storeDepot[token];
};
OS: Windows 10 Pro
apollo-client: 1.9.2
react-redux: 5.0.6
So, I'm attempting to read 'connect' a graphql resultset to redux but am receiving the above mentioned error message. My code is as follows:
import { connect } from 'react-redux';
class PhotoGrid extends React.Component {
render () {
const { data } = this.props;
const isNewPage = this.props.location.pathname.includes('new');
if (data.loading) {
return <p>Loading ...</p>;
}
if (data.error) {
return <p>{data.error.message}</p>;
}
return (
<div>
<div>Total record count: {data._allPostsesMeta.count}</div>
<div className="photo-grid">
{ data.allPostses.map( (post,i) => <Photo {...this.props} key={i} postIndexID={i} post={post} />) }
</div>
{isNewPage && (
<div>
<div onClick={() => this.previousPage()}>
Previous
</div>
<div onClick={() => this.nextPage()}>
Next
</div>
</div>
)}
</div>
);
}
};
const allPostsCommentsQuery = graphql(All_Posts_Comments_Query, {
options: ownProps => {
const page = parseInt(ownProps.match.params.page, 10);
const isNewPage = ownProps.location.pathname.includes('new');
const skip = isNewPage ? (page - 1) * parseInt(PRODUCTS_PER_PAGE) : 0;
const first = isNewPage ? parseInt(PRODUCTS_PER_PAGE) : parseInt(PRODUCTS_PER_PAGE);
const orderBy = isNewPage ? OrderBy : null;
fetchPolicy: 'network-only';
return {
variables: {
__offline__: true,
first,
skip,
orderBy,
},
}
},
});
export default connect(allPostsCommentsQuery)(PhotoGrid)
What am I overlooking here?