access RTK-query data in createSlice action - redux-toolkit

what woud be the correct way to access RTK-query data inside createSlice reducers?
Like, for example 'select all' functionality in the code below.
is it possible to access current useGetOrdersQuery() data inside toggleSelectAll() action?
or the only/best way to implement 'select/deselect all' would be to pass useGetOrdersQuery() data to toggleSelectAll() action as action payload?
dashboardSlice.js
const initialState = {
selectedIds: [],
};
export const dashboardSlice = createSlice({
name: 'dashboard',
initialState,
reducers: {
toggleSelectAll: (state, action) => {
//get "useGetOrdersQuery" data id's and assign to state.selectedIds
}
}
});
export const { toggleSelectAll } = dashboardSlice.actions;
export const selectSelectedIds = state => state.dashboard.selectedIds;
orders-lsit.js
import { useGetOrdersQuery } from './api'
import { toggleSelectAll, selectSelectedIds } from './dashboardSlice';
const OrdersList = () => {
const {data} = useGetOrdersQuery(123);
const dispatch = useDispatch();
const selectedIds = useSelector(selectSelectedIds);
return (
<div>
<button onClick={() => dispatch(toggleSelectAll())}>
select/deselect all
</button>
{data.map(o => (
<div>
<h2>{o.name}</h2>
<input
type="checkbox"
checked={selectedIds.includes(o.id)}
/>
</div>
))}
</div>
)
}
api.js
export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
endpoints: (builder) => ({
getOrders: builder.query({
query: (userId) => `${userId}/orders`,
providesTags: [{ type: 'Orders', id: 'LIST' }]
})
})
});
export const { useGetOrdersQuery } = api;

if you just want to save the ids you can do this :
const initialState = {
selectedIds: [],
};
export const dashboardSlice = createSlice({
name: 'dashboard',
initialState,
reducers: {
toggleSelectAll: (state, action) => {
//get "useGetOrdersQuery" data id's and assign to state.selectedIds
const { ids } = action.payload;
state.selectedIds = ids;
return state;
}
}
});
export const { toggleSelectAll } = dashboardSlice.actions;
export const selectSelectedIds = state => state.dashboard.selectedIds;
and
import { useGetOrdersQuery } from './api'
import { toggleSelectAll, selectSelectedIds } from './dashboardSlice';
const OrdersList = () => {
const {data} = useGetOrdersQuery(123);
const dispatch = useDispatch();
const selectedIds = useSelector(selectSelectedIds);
// you can pass the list of ids as a payload to your action and store it for later use.
return (
<div>
<button onClick={() => dispatch(toggleSelectAll({ids: data.map(item => item.id}))}>
select/deselect all
</button>
{data.map(o => (
<div>
<h2>{o.name}</h2>
<input
type="checkbox"
checked={selectedIds.includes(o.id)}
/>
</div>
))}
</div>
)
}
you have something like this too:
check out this link
const store = useStore();
const allDataOfAllQueries = store.getState().api.queries;
console.log(Object.values(allDataOfAllQueries);

Related

How to stop getting an undefined value when changing a select value using useState and useEffect

I have the following code in my first component, where I fetch some data from which I need to pull an array of strings and send it as values to my Material UI select component:
const Logs = () => {
const [data, setData] = useState({})
const [usersList, setUsersList] = useState([])
const [user, setUser] = useState(null)
const getData = async () => {
try {
const { data } = await axios.request({
method: "GET",
baseURL: 'some url',
url: `/logger`,
headers: {
"Content-Type": "application/json",
},
withCredentials: true,
});
setData(data);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
( async () => {
await getData();
})()
}, []);
const isEmpty = obj => Object.keys(obj).length === 0;
useEffect(() => {
if(isEmpty(data) === false) {
setUsersList(data.userNames)
}
console.log('Data', data) //{userNames: ['Admin', 'User1', 'User2']
})
useEffect(() => {
setUser(usersList[0]) //setting the user to Admin
})
const handleUserChange = (event) => {
const value = event.target.value;
setUser(value);
};
return (
<div>
<CssBaseline />
{<LogsSelect
labelId="logs-user-select-label"
selectId="logs-user-select"
handleChange={handleUserChange}
value={user}
list={usersList}
label='User'
/>
}
)
}
My select is defined as a separate (generic) component:
const LogsSelect = (labelId, selectId, handleChange, value, list, label) => {
return (
<FormControl
className={classes.form}
style={{ minWidth: "140px"}}
>
<InputLabel id={labelId}>{label}</InputLabel>
<Select
className={classes.select}
labelId={labelId}
id={selectId}
onChange={handleChange}
value={value}
>
{value && list?.map((el, index) => (
<MenuItem value={el} key={index}>
{el}
</MenuItem>
))}
</Select>
</FormControl>
)}
I get the following error:
Material-UI: You have provided an out-of-range value undefined for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are "". This is happening when rendering the components. I haven't even managed to get my list of values as options in my select, and then try and change the value.
Pass defaultValue="" to the <Select />
...
<Select
defaultValue=""
>
...
</Select>
...

may i use this code for finduserDetail in react using redux-thunk dispatch to calling function

This code for finduserdetail by hitting function with help of dispatch method and passing (match.params.id) not working, even function not called as I know on dispatch method it should be called how may I call this so that our stat could be update in root.js file then I can show detail on my ui by using useselector
in productDetail.js
import { Fragment } from "react";
import Carousel from "react-material-ui-carousel";
import {useParams} from "react-router-dom";
import './ProductDetails.css';
import {useDispatch} from "react-redux";
import { useEffect } from "react";
import { getProductDetail } from "../../actions/productAction";
const ProductDetails = () =>{
console.log("hello this is detail")
const dispatch= useDispatch();
let params = useParams()
const id= params.id;
// const {product,error} = useSelector(
// (state) =>state.product)
useEffect(()=>{
dispatch(getProductDetail(id))
}, [dispatch, id])
return(
<Fragment>
<div className="ProductDetails">
<div>
<Carousel>
{/* {product.images &&
product.images.map((item,i)=>{
<img
className="CarouselImage"
key={item.url}
src={item.url}
alt={`${i} Slide`}
/>
})} */}
</Carousel>
</div>
</div>
</Fragment>
);
};
export default ProductDetails
and using for calling api for findproductDetail using getProductDetail in productAction.js
export const getProductDetail =(id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILES_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILES_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILES_FAIL,
payload: error.response.data.message,
});
}
};
and one other file productReducer.js
export const productDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILES_REQUEST:
return {
loading: true,
...state,
};
case PRODUCT_DETAILES_SUCCESS:
return {
loading: false,
product: action.payload.product,
};
case PRODUCT_DETAILES_FAIL:
return {
loading: false,
error: action.payload,
};
and another file store.js
import { legacy_createStore as createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { productDetailsReducer, productReducer } from './reducers/productReducer';
const reducer = combineReducers({
products: productReducer,
product: productDetailsReducer,
});
let initialState ={};
const middleware = [thunk];
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
These stuff not working. I am quite beginner in React programming
import { Fragment } from "react";
import Carousel from "react-material-ui-carousel";
import {useParams} from "react-router-dom";
import './ProductDetails.css';
import {useDispatch} from "react-redux";
import { useEffect } from "react";
import { getProductDetail } from "../../actions/productAction";
const ProductDetails = () =>{
console.log("hello this is detail")
const dispatch= useDispatch();
let params = useParams()
const id= params.id;
// const {product,error} = useSelector(
// (state) =>state.product)
useEffect(()=>{
dispatch(getProductDetail(id))
}, [dispatch, id])
return(
<Fragment>
<div className="ProductDetails">
<div>
<Carousel>
{/* {product.images &&
product.images.map((item,i)=>{
<img
className="CarouselImage"
key={item.url}
src={item.url}
alt={`${i} Slide`}
/>
})} */}
</Carousel>
</div>
</div>
</Fragment>
);
};
export default ProductDetails
and using for calling api for findproductDetail using getProductDetail in productAction.js
export const getProductDetail =(id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILES_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILES_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILES_FAIL,
payload: error.response.data.message,
});
}
};
and one other file productReducer.js
export const productDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILES_REQUEST:
return {
loading: true,
...state,
};
case PRODUCT_DETAILES_SUCCESS:
return {
loading: false,
product: action.payload.product,
};
case PRODUCT_DETAILES_FAIL:
return {
loading: false,
error: action.payload,
};
and another file store.js
import { legacy_createStore as createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { productDetailsReducer, productReducer } from './reducers/productReducer';
const reducer = combineReducers({
products: productReducer,
product: productDetailsReducer,
});
let initialState ={};
const middleware = [thunk];
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
The most important stuff my redux state is not updating because of id matching condition once if
state will get update I am checking using redux tool

How to resolve Error " Too many re-renders. React limits the number of renders to prevent an infinite loop." in react native?

I have develop form to submit complaint by selecting product prom picker. So I externally implement the picker and then use it in complaint submission form. For that I was needed to take selectedValue state into complaint submission form by using function handle change. After i implement that faction and change appropriate places regarding to the tutorial link : [https://github.com/reactjs/reactjs.org/issues/1689][1]
But when I navigate to the complaint submission form it says the error as " Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."So help me to resove and please confirm am I follow the above tutorial correctly.
Complaint submission form:
import * as React from 'react';
import {Button, View, Text, ScrollView, StyleSheet, Alert} from 'react-native';
import {Appbar} from 'react-native-paper';
import {TextInput, HelperText} from 'react-native-paper';
import {useEffect, useState} from 'react';
import AsyncStorage from '#react-native-community/async-storage';
import ProductPicker from './ProductPicker';
const ComplaintSubmission = ({navigation}) => {
const [productID , setproductID] = useState('');
const [description , setdescription] = useState('');
const [token, setToken] = useState('');
useEffect(() => {
saveToken();
}, []);
function handleChange(newValue){
setproductID(newValue);
}
const saveToken = async () => {
const token = await AsyncStorage.getItem('userToken');
console.log('token from storage', token);
setToken(token);
}
const send = () =>{
fetch("http://10.0.2.2:3000/customer/lodge-complaint", {
method: "post",
headers: {
'Content-Type': 'application/json',
'Authentication': `Bearer ${token}`
},
body: JSON.stringify({
description : description,
productID : value
})
})
}
const openAlert = () => {
Alert.alert(
"Complaint Successfully Submitted",
"We review it as soon as possible. Thank you for reaching for us!",
[{
text: "OK",
onPress : () => navigation.navigate("DashboardDrawer" ),
}]
);
}
return (
<ScrollView>
<Appbar.Header>
<Appbar.BackAction onPress={() => navigation.goBack()} />
<Appbar.Content title="Submit Complaint" />
<Appbar.Action icon="magnify" onPress={() => navigation.openDrawer()} />
</Appbar.Header>
<Text>Plese Fill the following</Text>
<View>
{/*{console.log('renderer token', token)}*/}
<ProductPicker value={productID} onValueChange = {handleChange()} />
<HelperText type="info">
Make sure select the correct Product
</HelperText>
</View>
<TextInput
style={styles.PIDstyle}
label="Description"
onChangeText = {(description) => setdescription(description)}
/>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>This is submittion</Text>
<Button onPress={() => {send(); openAlert();}} title="Submit Complaint" />
</View>
</ScrollView>
);
};
export default ComplaintSubmission;
const styles = StyleSheet.create({
PIDstyle: {
marginTop: 30,
marginLeft: 10,
marginRight: 10,
},
});
And this is the picker component:
import React, {useEffect, useState} from 'react';
import {View, StyleSheet} from 'react-native';
import {Picker} from '#react-native-picker/picker';
import AsyncStorage from '#react-native-community/async-storage';
const ProductPicker = () => {
const [selectedValue, setSelectedValue] = useState('');
const [productDetails, setproductDetails] = useState([]);
console.log('product id---', selectedValue);
useEffect(() => {
getProductList();
}, []);
function handleChange(event){
props.onValueChange(event.target.value);
}
const getProductList = async () => {
const token = await AsyncStorage.getItem('userToken');
console.log(' function eka athule------', token);
fetch('http://10.0.2.2:3000/customer/get-all-products', {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authentication': `Bearer ${token}`,
},
})
.then((response) => response.json())
.then((json) => setproductDetails(json.data))
.catch((error) => console.error(error));
};
return (
<View style={styles.container}>
<Picker
selectedValue={selectedValue}
style={{height: 40, width: 150}}
onValueChange={(itemValue, itemIndex) => {
setSelectedValue(itemValue);
handleChange();
}}
>
{productDetails.map((item, index) => {
return (
<Picker.Item label={item.productName} value={props.item.productID} key={index}/>);
})}
</Picker>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 40,
alignItems: 'center',
},
});
export default ProductPicker;
Why don't you pass the itemValue to handleChange?
onValueChange={(itemValue, itemIndex) => {
setSelectedValue(itemValue);
handleChange(itemValue);
}}
Then change the function:
function handleChange(value){
props.onValueChange(value);
}

unable to send an axios request from frontend to backend using useContext hook react native

I was trying to send a request to backend but i received this error message
'Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're %s %s on a released/nullified synthetic event. %s. If you must keep the original synthetic event around, use event.persist(). , accessing the method, timeStamp, This is a no-op function'
when i hit the button on my react native app i get that error message.
here is my signup file
import React, { useState, useContext}from 'react';
import { View, TouchableOpacity,StyleSheet} from 'react-native';
import { Card,Input,Button} from 'react-native-elements';
import {Context as AuthContext} from '../redux/authContext';
const SignUpScreen = ({navigation}) => {
const {state, signUp } = useContext(AuthContext)
const [firstName, setFirstName] = useState('');
const [lastName,setLastName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [telephoneNumber, setTelephoneNumber] = useState('');
return(
<View>
<Card>
<Input
placeholder="First Name"
value={firstName}
onChange={setFirstName}/>
<Input
placeholder="Last Name"
value={lastName}
onChange={setLastName}/>
<Input
placeholder="Email Address"
value={email}
onChange={setEmail}
autoCapitalize="none"
autoCorrect={false}/>
<Input
placeholder="Telephone Number"
value={telephoneNumber}
onChange={setTelephoneNumber}
/>
<Input
placeholder="Password"
value={password}
onChange={setPassword}
autoCapitalize="none"
autoCorrect={false}
secureTextEntry={true}
/>
<Button
title="Enter"
onPress={()=> signUp({firstName,lastName,email,telephoneNumber,password})}/>
</Card>
</View>
)
};
SignUpScreen.navigationOptions = {
headerShown: false
}
export default SignUpScreen;
here is my reducer file
import createContext from './createContext';
import mainApi from '../api/apiConnection';
const authReducer = (state, action) => {
switch (action.type){
default:
return state;
}
};
const signUp = (dispatch) => {
return async ({firstName, lastName, email, password, telephoneNumber }) => {
try {
const response = await mainApi.post('/signup',{firstName, lastName, email, password, telephoneNumber});
console.log(response.data)
} catch(err){
console.log(err.message)
}
};
};
const login = (dispatch) => {
return ({ email, password }) => {
};
}
const logOut = (dispatch) => {
return ()=> {
}
}
export const {Provider, Context} = createContext(
authReducer,
{signUp,login,logOut},
{isSignedIn: false}
);
here is my routes file
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose')
const jwt = require('jsonwebtoken')
const User = mongoose.model('User')
//endpoint post request
router.post('/signup', async (req,res) => {
const {firstName, lastName, email,telephoneNumber,password} = req.body;
//try catch to catch duplicate emails
try{
const user = new User({firstName, lastName, email,telephoneNumber,password});
//saves post request to the db
await user.save();
//creating a token
const token = jwt.sign({userId:user._id},'SECRET_SESSION')
res.send({token:token})
} catch(err){
return res.status(422).send(err.message)
}
});
router.post('/signin', async (req,res)=> {
const {email, password} =req.body;
if(!email || !password){
return res.status(422).send({error: 'Must provide email and password'})
}
const user = await User.findOne({email:email});
if (!user){
res.status(422).send({error: 'Invalid password or email'})
}
try {
await user.comparePassword(password);
const token = jwt.sign({userId:user._id},'SECRET_SESSION')
res.send({token:token})
} catch(err){
return res.status(422).send({error: 'Invalid password or email'})
}
});
module.exports = router;

React useEffect to obtain Autocomplete options (material UI) from Cloud Firestore

I'm trying to use react useEffect hook to get data from firestore and give it to the options attribute on a Material UI autocomplete select menu.
I have a collection in my firestore called "organisations". That document has an attribute called "shortName".
I'm trying to get the data from the collection and then use it to set the state on a property called orgList, which I can then use in the in the select menu.
This is what I'm trying.
import React, { useState, useEffect } from 'react';
import Checkbox from '#material-ui/core/Checkbox';
import TextField from '#material-ui/core/TextField';
import Autocomplete from '#material-ui/lab/Autocomplete';
import CheckBoxOutlineBlankIcon from '#material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '#material-ui/icons/CheckBox';
import firebase from "../../../../../firebase";
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;
export default function CheckboxesTags() {
const [orgList, setOrgList] = useState();
const [selectedOrgList, setSelectedOrgList] = useState();
useEffect(() => {
firebase
.firestore()
.collection("organisations")
.onSnapshot(snapshot => {
const orgList = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data(),
}))
setOrgList(orgList)
})
}, [orgList])
return (
<div>
<Autocomplete
multiple
id="checkboxes-tags-demo"
options={orgList}
disableCloseOnSelect
getOptionLabel={(option) => option.shortName}
renderOption={(option, { selected }) => (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.shortName}
</React.Fragment>
)}
style={{ width: 500 }}
renderInput={(params) => (
<TextField {...params}
variant="outlined"
label="Select Organisation"
placeholder="Acme Inc"
/>
)}
/>
</div>
);
}
The error message I'm getting says:
TypeError: Cannot read property 'shortName' of undefined
NEXT ATTEMPT
Using the suggestion from gdh below, this is the next attempt.
import React, { useState, useEffect } from 'react';
import Checkbox from '#material-ui/core/Checkbox';
import TextField from '#material-ui/core/TextField';
import Autocomplete from '#material-ui/lab/Autocomplete';
import CheckBoxOutlineBlankIcon from '#material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '#material-ui/icons/CheckBox';
import firebase from "../../../../../firebase";
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;
export default function CheckboxesTags() {
const [orgList, setOrgList] = useState([]);
const [selectedOrgList, setSelectedOrgList] = useState();
const [loading, setLoading ] = useState(true);
const [ error, setError ] = useState(false);
useEffect(() => {
const unsubscribe = firebase
.firestore()
.collection("organisations")
.onSnapshot((snapshot) => {
const orgList = snapshot.docs.map((doc) => ({
id: doc.id,
shortName: doc.shortName
}));
console.log(orgList)
setOrgList(orgList);
}, () => {
setError(true)
});
setLoading(false);
return() => unsubscribe();
}, [orgList]);
useEffect(() => {
firebase
.firestore()
.collection("organisations")
.get()
.then((snapshot) => {
const orgList = snapshot.docs.map((doc) => ({
id: doc.id,
shortName: doc.shortName
}));
setOrgList(orgList);
});
}, []);
return (
<div>
<Autocomplete
multiple
id="checkboxes-tags-demo"
options={orgList}
disableCloseOnSelect
getOptionLabel={(orgList) => orgList.shortName}
renderOption={(orgList, { selected }) => (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{orgList.shortName}
</React.Fragment>
)}
style={{ width: 500 }}
renderInput={(params) => (
<TextField {...params}
variant="outlined"
label="Select Organisation"
placeholder="Acme Inc."
/>
)}
/>
</div>
);
}
The console log prints both orgList ids, but the shortName is undefined.
I get an error that says:
TypeError: Cannot read property 'toLowerCase' of undefined .
In an attempt to solve this error, I added:
ignoreCase = {false}
to the Autocomplete head tag, but the same error persists. The console logs an error that says:
Warning: React does not recognize the ignoreCase prop on a DOM
element. If you intentionally want it to appear in the DOM as a custom
attribute, spell it as lowercase ignorecase instead. If you
accidentally passed it from a parent component, remove it from the DOM
element
I tried renaming shortName in firestore to 'short' to see if I could avoid the case sensitivity issue, but the same error persists (console logs short as undefined when it has a value in the firestore console).
I know the form is reading from firestore because when I try setting the option as the id of the document, the form loads and the id prints as the value.
you don't have initial values for orgList. Provide a blank array.
you are only registering onSnapshot callback which only executes when organisations collection is changed but you are not fetching any data on mount. This means that your autocomplete will only have values when someone make change in organisation collection. So maintain another useEffect and fetch the data.
refactored code
export default function CheckboxesTags() {
const [orgList, setOrgList] = useState([]);
const [selectedOrgList, setSelectedOrgList] = useState();
useEffect(() => {
firebase
.firestore()
.collection("organisations")
.onSnapshot((snapshot) => {
const orgList = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setOrgList(orgList);
});
}, []);
useEffect(() => {
firebase
.firestore()
.collection("organisations")
.get()
.then((snapshot) => {
const orgList = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setOrgList(orgList);
});
}, []);
//.... rest of code...
I found what worked - eventually. There seems to be an issue limiting reading single attribute from the firebase document. In my snapshot, I was trying to read: doc.shortName / doc.short. It needs to be:
shortName: doc.data().shortName,
I didn't end up needing the second .get useEffect as proposed by gdh.
Here is what worked for me:
import React, { useState, useEffect } from 'react';
import Checkbox from '#material-ui/core/Checkbox';
import TextField from '#material-ui/core/TextField';
import Autocomplete from '#material-ui/lab/Autocomplete';
import CheckBoxOutlineBlankIcon from '#material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '#material-ui/icons/CheckBox';
import firebase from "../../../../../firebase";
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;
export default function CheckboxesTags() {
const [orgList, setOrgList] = useState([]);
const [selectedOrgList, setSelectedOrgList] = useState();
const [loading, setLoading ] = useState(true);
const [ error, setError ] = useState(false);
useEffect(() => {
// if (doc.exists) {
const unsubscribe = firebase
.firestore()
.collection("organisations")
.onSnapshot((snapshot) => {
const orgList = snapshot.docs.map((doc) => ({
id: doc.id,
shortName: doc.data().shortName
}));
console.log(orgList)
setOrgList(orgList);
}, () => {
setError(true)
});
setLoading(false);
return() => unsubscribe();
}, [orgList]);
// useEffect(() => {
// firebase
// .firestore()
// .collection("organisations")
// .get()
// .then((snapshot) => {
// const orgList = snapshot.docs.map((doc) => ({
// id: doc.id,
// ...doc.data()
// }));
// setOrgList(orgList);
// });
// }, []);
return (
<div>
<Autocomplete
multiple
id="checkboxes-tags-demo"
options={orgList}
disableCloseOnSelect
getOptionLabel={(option) => option.shortName}
renderOption={(orgList, { selected }) => (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{orgList.shortName}
</React.Fragment>
)}
style={{ width: 500 }}
renderInput={(params) => (
<TextField {...params}
variant="outlined"
label="Select Organisation"
placeholder="Acme Inc."
/>
)}
/>
</div>
);
}
As for the toLowerCase error - there is a filterOptions attribute that can be used on Autocomplete. I couldn't figure out how to get that working - but for now, that's a problem for another day.