Search functionality in reduxReact-native - javascript

I am trying to achieve search functionality in redux
I am using the following code but its not working but the same code is working in plain javascript but not with redux
searchItems: (name ) => async (dispatch) => {
let newData = []
dispatch({
type: types.SEARCH_ITEMS,
payload: (newData = DATA.filter((item) => {
const itemData = `${item.name.toUpperCase()}`;
const textData = name.toUpperCase();
itemData.indexOf(textData) > -1;
return newData;
})),
});
},
};
the newData is returning and empty array
export const reducer = (state = initialState, action) => {
const { type } = action;
switch (type) {
case types.SEARCH_ITEMS:
return [...action.payload];
default:
return state;
}
};
What am i dong wrong?

You should return from the filter callback true or false:
Try to do it this way:
searchItems: (name ) => async (dispatch) => {
dispatch({
type: types.SEARCH_ITEMS,
payload: DATA.filter((item) => {
const itemData = `${item.name.toUpperCase()}`;
const textData = name.toUpperCase();
return itemData.indexOf(textData) > -1;
}),
});
},
};

Related

React - how can I make the return of JSX wait until my useEffect() ended [duplicate]

I have fetch method in useEffect hook:
export const CardDetails = () => {
const [ card, getCardDetails ] = useState();
const { id } = useParams();
useEffect(() => {
fetch(`http://localhost:3001/cards/${id}`)
.then((res) => res.json())
.then((data) => getCardDetails(data))
}, [id])
return (
<DetailsRow data={card} />
)
}
But then inside DetailsRow component this data is not defined, which means that I render this component before data is fetched. How to solve it properly?
Just don't render it when the data is undefined:
export const CardDetails = () => {
const [card, setCard] = useState();
const { id } = useParams();
useEffect(() => {
fetch(`http://localhost:3001/cards/${id}`)
.then((res) => res.json())
.then((data) => setCard(data));
}, [id]);
if (card === undefined) {
return <>Still loading...</>;
}
return <DetailsRow data={card} />;
};
There are 3 ways to not render component if there aren't any data yet.
{data && <Component data={data} />}
Check if(!data) { return null } before render. This method will prevent All component render until there aren't any data.
Use some <Loading /> component and ternar operator inside JSX. In this case you will be able to render all another parts of component which are not needed data -> {data ? <Component data={data} /> : <Loading>}
If you want to display some default data for user instead of a loading spinner while waiting for server data. Here is a code of a react hook which can fetch data before redering.
import { useEffect, useState } from "react"
var receivedData: any = null
type Listener = (state: boolean, data: any) => void
export type Fetcher = () => Promise<any>
type TopFetch = [
loadingStatus: boolean,
data: any,
]
type AddListener = (cb: Listener) => number
type RemoveListener = (id: number) => void
interface ReturnFromTopFetch {
addListener: AddListener,
removeListener: RemoveListener
}
type StartTopFetch = (fetcher: Fetcher) => ReturnFromTopFetch
export const startTopFetch = function (fetcher: Fetcher) {
let receivedData: any = null
let listener: Listener[] = []
function addListener(cb: Listener): number {
if (receivedData) {
cb(false, receivedData)
return 0
}
else {
listener.push(cb)
console.log("listenre:", listener)
return listener.length - 1
}
}
function removeListener(id: number) {
console.log("before remove listener: ", id)
if (id && id >= 0 && id < listener.length) {
listener.splice(id, 1)
}
}
let res = fetcher()
if (typeof res.then === "undefined") {
receivedData = res
}
else {
fetcher().then(
(data: any) => {
receivedData = data
},
).finally(() => {
listener.forEach((cb) => cb(false, receivedData))
})
}
return { addListener, removeListener }
} as StartTopFetch
export const useTopFetch = (listener: ReturnFromTopFetch): TopFetch => {
const [loadingStatus, setLoadingStatus] = useState(true)
useEffect(() => {
const id = listener.addListener((v: boolean, data: any) => {
setLoadingStatus(v)
receivedData = data
})
console.log("add listener")
return () => listener.removeListener(id)
}, [listener])
return [loadingStatus, receivedData]
}
This is what myself needed and couldn't find some simple library so I took some time to code one. it works great and here is a demo:
import { startTopFetch, useTopFetch } from "./topFetch";
// a fakeFetch
const fakeFetch = async () => {
const p = new Promise<object>((resolve, reject) => {
setTimeout(() => {
resolve({ value: "Data from the server" })
}, 1000)
})
return p
}
//Usage: call startTopFetch before your component function and pass a callback function, callback function type: ()=>Promise<any>
const myTopFetch = startTopFetch(fakeFetch)
export const Demo = () => {
const defaultData = { value: "Default Data" }
//In your component , call useTopFetch and pass the return value from startTopFetch.
const [isloading, dataFromServer] = useTopFetch(myTopFetch)
return <>
{isloading ? (
<div>{defaultData.value}</div>
) : (
<div>{dataFromServer.value}</div>
)}
</>
}
Try this:
export const CardDetails = () => {
const [card, setCard] = useState();
const { id } = useParams();
useEffect(() => {
if (!data) {
fetch(`http://localhost:3001/cards/${id}`)
.then((res) => res.json())
.then((data) => setCard(data))
}
}, [id, data]);
return (
<div>
{data && <DetailsRow data={card} />}
{!data && <p>loading...</p>}
</div>
);
};

Get the EditorState(DraftJS) from DB with Redux

I want to repopulate the editor's state with the values i have saved to Firebase.
OnSubmit:
sendNotes = (e) => {
e.preventDefault();
let contentState = this.state.editorState.getCurrentContent()
let note = { content: convertToRaw(contentState) }
note["content"] = JSON.stringify(note.content);
this.props.createNote(note.content);
};
NoteAction:
export function getNote() {
return (dispatch) => {
database.on("value", (snapshot) => {
dispatch({
type: LOAD_NOTE,
payload: snapshot.val(),
});
});
};
}
noteReducer:
export default function (state = {}, action) {
switch (action.type) {
case LOAD_NOTE:
return action.payload;
default:
return state;
}
}
REDUX/firebase:
{
type: 'LOAD_NOTE',
payload: {
'-MNOwBIWNqY_ZFDO4ILs': '{"blocks":[{"key":"c27el","text":"ASD!!!!!!!!!!!!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}',
'-MNOyHLvaORxEmuuJmzJ': '{"blocks":[{"key":"c27el","text":"HELLO WORLD","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}',
'-MNOyP50oGHRLiP3T5_h': '{"blocks":[{"key":"c27el","text":"This is a REDUX STORE","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}'
}
}
MapStateToProps:
function mapStateToProps(state, ownProps) {
return {
note: state.notes,
};
}
export default connect(mapStateToProps, { getNote })(TextEditor);
My Code:
componentDidMount() {
this.props.getNote();
}
componentWillReceiveProps = (nextProps) => {
if (nextProps.note !== null) {
let item = "";
_.map(nextProps.note, (note, key) => {
return (item = note);
});
this.setState({
editorState: EditorState.createWithContent(convertFromRaw(JSON.parse(item))),
});
}
};
The code is working but I'm not 100% sure about these lifecycle methods & if the code i have written is 'stable'. I am stuck with this, please :).

React Native - Class Component to Functional Component (UseEffect: state undefined)

I need to convert my Class Components code to Functional Hooks Components. I have the Class Components logic below that works. However for me to implement Context Api I need to convert it to hooks.
I get storeList undefined when I console log it and this error...
TypeError: undefined is not an object (evaluating 'storeList'.map).
Is there a way I can make introduce a state inside a UseEffect? Thank you in advance
const { data, status } = useQuery('stores', fetchStores)
const [isSelected, setIsSelected] = useState(false)
const storeList = data
useEffect(() => {
let array = storeList.map((item, index) => {
isSelected = false
return { ...item }
})
setIsSelected({ ...isSelected, array: { ...storeList.array } })
selectHandler()
}, [])
const selectHandler = (ind) => {
let array = storeList.map((item, index) => {
if (ind == index) {
item.isSelected = !item.isSelected
}
return { ...item }
})
setIsSelected({ ...isSelected, array: { ...storeList.array } })
}
Here is the same code as Class component and it works perfectly
async componentDidMount() {
let array = this.state.storeList.map((item, index) => {
this.isSelected = false
return { ...item }
})
this.setState({ storeList: array })
}
selectionHandler = (ind) => {
const { storeList } = this.state
let array = storeList.map((item, index) => {
if (ind == index) {
item.isSelected = !item.isSelected
}
return { ...item }
})
this.setState({ storeList: array })
}
Try This:
const { data, status } = useQuery('stores', fetchStores)
const [isSelected, setIsSelected] = useState(false)
const storeList = data
useEffect(() => {
let array = storeList.map((item, index) => {
isSelected = false
return { ...item }
})
setIsSelected(state => ({ ...state, array: { ...storeList.array } }));
selectHandler()
}, [])
const selectHandler = (ind) => {
let array = storeList.map((item, index) => {
if (ind == index) {
item.isSelected = !item.isSelected
}
return { ...item }
})
setIsSelected(state => ({ ...state, array: { ...storeList.array } }));
}
Reference: https://stackoverflow.com/a/63522873/10994570
This worked!! I hope it can help someone else. Thanks
const { data, status } = useQuery('stores', fetchStores)
const [isSelected, setIsSelected] = useState(false)
const storeList = data
useEffect(() => {
handlerControl()
}, [])
const handlerControl = async () => {
try {
let array = await storeList.map((item, index) => {
isSelected = false
return { ...item }
})
setIsSelected(array)
} catch (e) {
console.log(e)
}
}
const selectHandler = async (ind) => {
//alert('pressed')
try {
let array = await storeList.map((item, index) => {
if (ind == index) {
item.isSelected = !item.isSelected
}
return { ...item }
})
setIsSelected(array)
console.log(index)
} catch (e) {
console.log(e)
}
}

useReducer not updating the array of items in sync, being a render late

A video with the behavior, I am clicking one time in 'A' and one time 'D', alternatively and is like there is two states, really strange!
https://www.loom.com/share/ba7a97f008b14529b15dca5396174c8c
And here is the action to update the description!
if (action.type === 'description') {
const { payload } = action;
const { description } = payload;
const objIndex = state.findIndex(obj => obj === payload.state);
state[objIndex].description = description;
return [...state];
}
And this is the big picture as requested, I tried to simplify to the code that I am testing in description input:
//outside component
const reducer = (state, action) => {
if (action.type === 'initialState') {
const { payload } = action;
console.log('state', state);
console.log('payload', payload);
return state.concat(payload);
}
if (action.type === 'description') {
const { payload } = action;
const { description } = payload;
const objIndex = state.findIndex(obj => obj === payload.state);
state[objIndex].description = description;
return [...state];
}
};
//inside component
const [states, dispatch] = useReducer(reducer, []);
function updateInitialState(value) {
dispatch({ type: 'initialState', payload: value });
}
function updateDescription(payload) {
dispatch({ type: 'description', payload });
}
useEffect(() => {
states.forEach(state => {
const descriptionInput = (state.status === undefined || state.status === 'available') && (
<FormInput
name="description"
label="Descrição"
input={
<InputText
value={state.description || ''}
onChange={({ target: { value } }) => {
const payload = { description: value, state };
updateDescription(payload);
}}
placeholder="Descrição"
/>
}
/>
);
const index = states.findIndex(e => e === state);
const updateArray = arrayInputs;
updateArray[index] = [descriptionInput];
setArrayInputs(updateArray);
});
}, [states]);

fetching json with redux-thunk

I have a issue with fetching json from server. When I'm trying to getState() from store there's "undefined" value. I'm using "redux-thunk". Help!
Store and state:
const store = createStore(reducer, applyMiddleware(thunk));
const initialState = {
datas: [],
loading: false
};
Reducer:
function reducer(state = initialState, action) {
switch(action.type){
case FETCH_DATA_BEGIN:
return {
...state,
loading: true
};
case FETCH_DATA_SUCCESS:
return {
...state,
datas: action.payload.TableData
};
default:
return state;
};
}
Actions:
function fetchData() {
return dispatch => {
dispatch(fetchDataBegin());
return fetch("http://www.blblblblb.com")
.then(res => res.json())
.then(json => {
dispatch(fetchDataSuccess(json.TableData));
return json.TableData;
})
};
}
const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
const fetchDataSuccess = TableData => ({
type: FETCH_DATA_SUCCESS,
payload: {TableData}
});
const FETCH_DATA_BEGIN = 'FETCH_DATA_BEGIN';
const fetchDataBegin = () => ({
type: FETCH_DATA_BEGIN
});
Thanks!

Categories

Resources