Handle async operation in Redux - reactjs

I am trying to render post.paragraph coming from the Redux store.
This is the code I am using:
const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails;
const editorContent = post ?
EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) :
EditorState.createEmpty();
const [editorState, setEditorState] = useState({ editorState: editorContent });
const handleEditorChange = (editorState) => { setEditorState({ editorState }) }
const submitHandler = (e) => {
e.preventDefault();
dispatch(
updatePost({
_id: id,
title,
image,
images,
paragraph: JSON.stringify(
convertToRaw(editorState.editorState.getCurrentContent())
),
})
);
};
<Editor
editorState={editorState.editorState}
onEditorStateChange={handleEditorChange}
/>
Though it seems like it takes time for post.paragraph to display therefore my app fails. In fact, if I console.log(post.paragraph) I get "undefined" twice and only then I get my post.paragraph displayed.
To fix the issue i tried to put everything in an if statement like this:
const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails;
const content = (async (err, res) => {
const editorContent = await post.paragraph;
if (post.paragraph) {
res.send({ editorContent: EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) });
} else {
res.send({ editorContent: EditorState.createEmpty()});
}
return editorContent;
})
const [editorState, setEditorState] = useState({ editorState: content });
const handleEditorChange = (editorState) => { setEditorState({ editorState }) }
const submitHandler = (e) => {
e.preventDefault();
dispatch(
updatePost({
_id: id,
title,
image,
images,
paragraph: JSON.stringify(
convertToRaw(editorState.editorState.getCurrentContent())
),
})
);
};
<Editor
editorState={editorState.editorState}
onEditorStateChange={handleEditorChange}
/>
But now the error I get is the following:
I also tried the following, but i get the same error:
const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails;
const editorContent = !loading ?
EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) :
EditorState.createEmpty();
const [editorState, setEditorState] = useState({ editorState: editorContent });
const handleEditorChange = (editorState) => { setEditorState({ editorState }) }
const submitHandler = (e) => {
e.preventDefault();
dispatch(
updatePost({
_id: id,
title,
image,
images,
paragraph: JSON.stringify(
convertToRaw(editorState.editorState.getCurrentContent())
),
})
);
};
<Editor
editorState={editorState.editorState}
onEditorStateChange={handleEditorChange}
/>
How should I tackle this async request? Many thanks!

Related

data is not reloading after being saved

I'm storing data using API, it saves successfully, but it's not reloading in the datagrid. I have manually refresh the entire page to view the data. I tried to put the storing variable in a function, then call that function, but it's not rendering I guess. kindly help me. Thank you in advance
here's the code
const ContactDataGrid = ({ rows, columns }) => {
const [platform, setPlatform] = useState([]);
const [searchText, setSearchText] = useState('');
const [Rows, setRows] = useState([]);
const [open, setOpen] = useState(false);
const [formInputData, setformInputData] = useState(
{
name: '',
details: '',
}
);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const handleChange = (evnt) => {
setOpen(true)
const newInput = (data) => ({
...data,
[evnt.target.name]: evnt.target.value
});
setformInputData(newInput);
}
const showData = () => setRows(rows);
useEffect(() => {
setPlatform(rows);
showData();
}, [rows]);
console.log()
const handleSubmit = (evnt) => {
evnt.preventDefault();
const formData = new FormData(); //formdata object
formData.append('nickname', formInputData.nickname); //append the values with key, value pair
formData.append('target', formInputData.target);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
axios.post('http://localhost:8006/api/v2/save/beneficiary', formData, config)
.then(response => {
if (response.data.success === true) {
showData()
alert(response.data.message)
}
})
.catch(error => {
alert(error.message);
});
setformInputData({ nickname: "", target: "" });
setOpen(false);
}
function escapeRegExp(value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
const requestSearch = (searchValue) => {
const searchRegex = new RegExp(escapeRegExp(searchValue), 'i');
const filteredRows = platform.filter((row) => {
return Object.keys(row).some((field) => {
return searchRegex.test(row[field]?.toString() || '');
});
});
setRows(filteredRows);
};
I think when you request success the variable rows don't change so show data load the old data. You can trigger when post data you request fetch data again and change datagrid.

displaying a sucess message using email.js

I'm wondering how I can display a "message sent successfully" message after the user has submitted the form?
Any help would be greatly appreciated. Right now the message is sent but there is no success message displayed.
export const Contact = (props) => {
const [{ name, email, message }, setState] = useState(initialState)
const handleChange = (e) => {
const { name, value } = e.target
setState((prevState) => ({ ...prevState, [name]: value }))
}
const clearState = () => setState({ ...initialState })
const handleSubmit = (e) => {
e.preventDefault()
console.log(name, email, message)
emailjs
.sendForm(
'service_8cyr6cf', 'template_0koo5jf', e.target, 'TtcKG0LCV4-mP5FnV'
)
.then(
(result) => {
console.log(result.text)
clearState()
},
(error) => {
console.log(error.text)
}
)
}
emailjs only handles the sending email part. If you want to display something on your UI, you need to create some HTML to display it.
Something like:
export const Contact = (props) => {
const [{ name, email, message }, setState] = useState(initialState)
const [statusMessage, setStatusMessage] = useState("");
const handleChange = (e) => {
const { name, value } = e.target
setState((prevState) => ({ ...prevState, [name]: value }))
}
const clearState = () => setState({ ...initialState })
const handleSubmit = (e) => {
e.preventDefault()
console.log(name, email, message)
emailjs
.sendForm(
'service_8cyr6cf', 'template_0koo5jf', e.target, 'TtcKG0LCV4-mP5FnV'
)
.then(
(result) => {
console.log(result.text, result.status);
clearState();
setStatusMessage("Email sent success");
},
(error) => {
console.log(error.text);
setStatusMessage(`${error.text} happened`);
}
)
}
return
(
<div>
<form></form>
<p>{statusMessage}</p>
</div>
)

react hooks useState consuming object

I am not sure how to make it correctly so I can pass object to useState
const App = () => {
const [weatherData, setWeatherData] = useState({data: "", time: ""});
useEffect(() => {
axios.get(apiUrl).then(response => {
setWeatherData({...weatherData, data: response.data, time: timestamp});
});
}, []);
return <div>{weatherData && <Weather data={weatherData.data} />}</div>;
};
when I do the same just with useState() and setWeatherData(response.data) it works fine but I would like to add the time
Have you tried the following:
setWeatherData({
...response.data,
time: timestamp,
});
P.S. Let me know if I understood you correctly.
UPD
Other option, if you need to access the current state:
useEffect(() => {
axios.get(apiUrl).then(response => {
const timestamp = Date.now().timestamp;
setWeatherData((prevWeatherData) => ({
...prevWeatherData,
data: response.data,
time: timestamp,
}));
});
}, []);
Try this:
const App = () => {
const [weatherData, setWeatherData] = useState(null);
useEffect(() => {
async function fetchWeather () {
const response = await axios.get(apiUrl)
setWeatherData({data: response.data, time: new Date().getTime()});
}
fetchWeather()
}, [weatherData]);
return (
<>
{weatherData && <Weather data={weatherData.data} />}
</>
);
};

Wait for useLazyQuery response

I need to call a query when submit button is pressed and then handle the response.
I need something like this:
const [checkEmail] = useLazyQuery(CHECK_EMAIL)
const handleSubmit = async () => {
const res = await checkEmail({ variables: { email: values.email }})
console.log(res) // handle response
}
Try #1:
const [checkEmail, { data }] = useLazyQuery(CHECK_EMAIL)
const handleSubmit = async () => {
const res = await checkEmail({ variables: { email: values.email }})
console.log(data) // undefined the first time
}
Thanks in advance!
This works for me:
const { refetch } = useQuery(CHECK_EMAIL, {
skip: !values.email
})
const handleSubmit = async () => {
const res = await refetch({ variables: { email: values.email }})
console.log(res)
}
After all, this is my solution.
export function useLazyQuery<TData = any, TVariables = OperationVariables>(query: DocumentNode) {
const client = useApolloClient()
return React.useCallback(
(variables: TVariables) =>
client.query<TData, TVariables>({
query: query,
variables: variables,
}),
[client]
)
}
You could also use the onCompleted option of the useLazyQuery hook like this:
const [checkEmail] = useLazyQuery(CHECK_EMAIL, {
onCompleted: (data) => {
console.log(data);
}
});
const handleSubmit = () => {
checkEmail({ variables: { email: values.email }});
}
In case someone wants to fetch multiple apis at single load, it could be achieved like this.
On Demand Load > e.g. onClick, onChange
On Startup > e.g. useEffect
import { useLazyQuery } from "#apollo/client";
import { useState, useEffect } from "react";
import { GET_DOGS } from "../../utils/apiUtils";
const DisplayDogsLazy = () => {
const [getDogs] = useLazyQuery(GET_DOGS);
const [data, setData] = useState([]);
useEffect(() => {
getAllData();
}, []);
const getAllData = async () => {
const response = await getDogs();
console.log("Awaited response >", response);
};
const handleGetDogsClick = async () => {
const response = await getDogs();
setData(response.data.dogs);
};
return (
<>
<button onClick={handleGetDogsClick}>Get Dogs</button>
{data?.length > 0 && (
<ul>
{data?.map((dog) => (
<li key={dog.id} value={dog.breed}>
{dog.breed}
</li>
))}
</ul>
)}
</>
);
};
export default DisplayDogsLazy;

Failed to read data form the fetched resource in React. (Cannot read property 'backdrop_path' of undefined)

I have fetched some data from the endpoint and stored it in the state. When I try to view the result in the console it works fine. But when I try to consume it in the component then it throws an error telling that the key is undefined. Here is my code and the heroImage is undefined, Help, please
const Home = () => {
const [state, setState] = useState({ movies: [] });
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const fetchMovies = async endpoint => {
setIsError(false);
setIsLoading(false);
const params = new URLSearchParams(endpoint);
if (!params.get("page")) {
setState(prev => ({
...prev,
movies: [],
searchItem: params.get("query")
}));
}
try {
const result = await fetch(endpoint)).json();
setState(prev => ({
...prev,
movies: [...prev.movies, result.results],
heroImage: prev.heroImage || result.results[0],
currentPage: result.page,
totalPage: result.total_pages
}));
} catch (error) {
setIsError(true);
}
setIsLoading(false);
};
useEffect(() => {
fetchMovies(`${API_URL}movie/popular?api_key=${API_KEY}&page=1`);
}, []);
return (
<>
<div className="rmdb-home">
<div>
<HeroImage
image={`${IMAGE_BASE_URL}${BACKDROP_SIZE}${state.heroImage.backdrop_path}`}
/>
<SearchBar />
</div>
</div>
</>
);
};
because your component trying to access heroImage when first render, but it's undefined
So you need a initial state for heroImage
like
const [state,setState]=useState({movies:[], heroImage: {}})

Resources