Export componenent after ajax call finishes in React - ajax

I want to export a component after the ajax call finishes. Here is the below code, the output of below code is
exporting 1
exporting 3
exporting 4
exporting 2
But I want to execute it sequentially, My desired output is
exporting 1
exporting 2
exporting 3
exporting 4
import appLocaleData from "react-intl/locale-data/en";
import enMessages from "../locales/en_US.json";
import config from "config";
const lang = new Object();
console.log( " exporting 1" );
fetch(`${config.api.languageUrl}english.json`, {
method: "GET",
headers: {
"Content-Type": "application/octet-stream"
}
})
.then(res => res.json())
.then(json => {
Object.assign(lang, json);
console.log("json->", json);
console.log("lang->", lang);
console.log(lang._VIEW);
console.log( "exporting 2" );
});
console.log( "exporting 3" );
const EnLang = {
messages: {
...lang
},
locale: "en-US",
data: appLocaleData
};
console.log( "exporting 4" );
export default EnLang;
Is there anyway in react, I can perform this ?
Thanks,

No, there is no such thing as an asynchronous export in javascript. If you can be more clear about what you are trying to accomplish I might be able to suggest a possible approach, but as is I don't even understand how this has anything to do with React specifically
EDIT based on OP's reply:
try something like this...
export const LocalsContext = React.createContext([]);
const App = () => {
...
const [locals, setLocals] = useState([]);
useEffect(() => {
fetch(...)
.then(...)
.then(localsList => setLocals(localsList)
}, []);
return (
<LocalsContext.Provider value={locals}>
...
</LocalsContext.Provider>
)
}
export default App
and then in any component anywhere within your app you can access the locals like so:
const MyComponent = () => {
/*
* will re-render whenever the locals updates,
* i.e., will render once with [] as the value, then once the
* data is fetched it will render again with the actual locals value
*/
const locals = useContext(LocalsContext);
return <div>some component</div>
}

Related

how do I get the section title, sub_section_title and file in the formData in laravel

I am developing an application using laravel 8 and vuejs. I am trying to post form data from my vuejs to backend(laravel) but it is not working
The vuejs creates a subsection of a section which is add to an array of subsection inside the section array which is converted to string and added to a form data then sent as a request to my backend.
The frontend is working perfectly well but I cant access the data on my backend. How do I get the values of the course title, section title, sub section title and file added
Vuejs
<script>
import { reactive } from "vue";
import axios from "axios";
export default {
name: 'CreateCourse',
setup(){
const sections = reactive([{'section_title': '', 'sub_sections': [{'sub_section_title': '', 'file': '', 'url': ''}]}]);
const course = reactive({'title': '', 'description': ''});
const addSection = () => {
sections.push({"section_title": "", 'sub_sections': [{'sub_section_title': '', 'file': '', 'url': ''}]});
}
const addSubSection = (idx) => {
console.log('the value of idx is ', idx);
sections[idx].sub_sections.push({"sub_section_title": "", 'file': '', 'url': ''});
}
const uploadFile = (e, idx, i) => {
sections[idx].sub_sections[i].file = e.target.files[0];
sections[idx].sub_sections[i].url = URL.createObjectURL(sections[idx].sub_sections[i].file);
}
const createCourse = (e) => {
e.preventDefault();
let newCourse = JSON.stringify(course)
let newSection = JSON.stringify(sections)
const formData = new FormData();
formData.append("course", newCourse);
formData.append("sections", newSection);
showLoader(true);
axios.post('/api', form, { headers: {'Content-Type': 'multipart/form-data'}}).then(response =>
{
NotificationService.success(response.data.message);
showLoader(false);
course.title = '';
course.description = '';
}).catch(err => {
NotificationService.error(err.response);
showLoader(false);
});
}
return {
course,
createCourse,
sections,
addSection,
addSubSection,
uploadFile
}
}
</script>
laravel code
echo $request->get("title");
echo $request->get("description");
foreach($request->section_title as $titles)
{
echo $titles
}
foreach($request->section_sub_title as $sub_titles)
{
// info($sub_titles);
// return $sub_titles;
echo $sub_titles
}
{"course":{"title":"Frontend","description":"This is building web interface with html, css and javascript"},"sections":[{"section_title":"HTML","sub_sections":[{"sub_section_title":"What is HTML","file":{},"url":"blob:http://localhost:8080/ea0acc7d-34e6-4bff-9255-67794acd8fab"}]}]}
Bit tricky to understand where you're stuck, but let's give it a shot:
Does the api request actually reach your route (post -> /api), do you see in the network tab a post request to the route?
Have you tried running dd($request->all()) in the controller method so see what you're getting (just do this on the first line inside your method)?
Small gotcha moment:
Sometimes it helps to run the php artisan route:clearcommand

Apollo Client reactive variable state is not kept in cache after refreshing the page

I have Apollo Client running on my React app, and trying to keep authentication info in a Reactive Variable using useReactiveVar. Everything works in the dummy function when I first set the variable, however it resets the state after refreshing the app.
Here's my cache.js:
import { InMemoryCache, makeVar } from "#apollo/client";
export const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
isLoggedIn: {
read() {
return isLoggedInVar();
},
},
},
},
},
});
export const isLoggedInVar = makeVar();
export default cache;
Here's the component that reads the variable and renders different elements based on its state:
import React from "react";
import { useReactiveVar, useMutation } from "#apollo/client";
import MainButton from "../common/MainButton";
import { isLoggedInVar, userAddressVar } from "../../cache";
import { CREATE_OR_GET_USER } from "../../mutations/User";
const Profile = () => {
const isLoggedIn = useReactiveVar(isLoggedInVar);
const [createOrGetUser] = useMutation(CREATE_OR_GET_USER);
const handleCreateOrGetUser = () => {
const loginInput = {
address: 'text',
};
createOrGetUser({
variables: {
loginInput: loginInput,
},
}).then((res) => {
isLoggedInVar(true);
});
};
const profileComponent = isLoggedIn ? (
<div>Logged In</div>
) : (
<div onClick={handleCreateOrGetUser} className="profile-image"></div>
);
return (
<div className="profile-container">
{profileComponent}
</div>
);
};
export default Profile;
This component gets re-rendered properly when I invoke handleCreateOrGetUser, however, when I refresh the page, it resets the isLoggedInVar variable.
What would be the proper way to use Reactive Variables here to persist the cache?
It's not currently achievable using Apollo API according to their documentation.
There is currently no built-in API for persisting reactive variables,
but you can write variable values to localStorage (or another store)
whenever they're modified, and initialize those variables with their
stored value (if any) on app load.
There is a PR for that. https://github.com/apollographql/apollo-client/pull/7148

Redux Thunk action creator not dispatching fetching api

I have created a small react-redux application to fetch api data with redux-thunk middleware, for some reason, the action creator function that returns dispatch is not working.
Action Creators:
export const fetchUsers = () => {
console.log('test 1');
return dispatch => {
console.log('test 2');
dispatch(fetchUserRequest);
axios
.get("https://jsonplaceholder.typicode.com/users")
.then(response => {
const users = response.data;
dispatch(fetchUserSuccess(users));
})
.catch(error => {
const errorMessage = error.message;
dispatch(fetchUsersFailure(errorMessage));
});
};
};
console.log('test 1') is working but console.log('test 2') is not working.
Here is codesanbox link
You were missing a a few things:
in userTypes you were missing there is no _ when you create const types for example export const FETCH_USER_REQUEST = "FETCH USER REQUEST"; should be export const FETCH_USER_REQUEST = "FETCH_USER_REQUEST"; also in userActions import it from userTypes not userReducers it should be import {
FETCH_USER_REQUEST,
FETCH_USER_SUCCESS,
FETCH_USER_FAILURE
} from "./userTypes";
I have also fixed your userContainer, codesandbax: codesandbax

custom render connected react component with mock axios response - getBy* query misleading exception

I have a problem with updating props in my test after some code refactor. I use custom render and mock axios request but my component doesn't rerender (?). In my component in async ComponentDidMount() I do POST request. When I do manual test in browser everything works fine.
I receive exception produced by getByText():
Unable to find an element with the text: /Tasty Metal Keyboard/i. This
could be because the text is broken up by multiple elements. In this
case, you can provide a function for your text matcher to make your
matcher more flexible.
/** import React, mockAxios etc. */
const middleware = applyMiddleware(thunk);
const inputRootPath = document.createElement('input');
inputRootPath.id = 'rootPath';
inputRootPath.hidden = true;
inputRootPath.value = 'http://localhost/';
/**
*
* #param {*} ui komponent
* #param {*} param { initialState, store }
*/
export function renderWithRedux(
ui,
{ initialState, store = createStore(rootReducer, initialState, compose(middleware)) } = {},
) {
return {
...render(
<Provider store={store}>
{ui}
</Provider>,
{ container: document.body.appendChild(inputRootPath) }
),
store,
};
}
test('should render annex list', async () => {
const agBuilder = () => {
return {
ID: faker.random.number(),
NM: faker.commerce.productName(),
};
};
const agreements = [agBuilder(), agBuilder(), agBuilder(), agBuilder()];
mockAxios.post.mockResolvedValueOnce({ data: { ANLST: agreements } });
const { getByText, } = await renderWithRedux(<ConnectedAgreements />);
const optionRE = new RegExp(`${agreements[0].NM}`, 'i');
expect(getByText(optionRE)).toBeInTheDocument();
mockAxios.post.mockClear();
});
mocks/axios.js
export default {
get: jest.fn().mockResolvedValue({ data: {} }),
post: jest.fn().mockResolvedValue({ data: {} }),
};
I found solution. It turns out that after some code refactor I have another reducer which takes dispatch action invoked in CDM. It destructure axios response so my test code should have:
mockAxios.post.mockResolvedValueOnce({ data: { ANLST: agreements, CLS: {}, EXLDT: {} } });
Missing CLS and EXLDT properties casue test fail. Jest however doesn't print error that something is missing or undefined ¯_(ツ)_/¯ . Exception produced by getByText() was misleading.

substate.get() is not a function using React Boilerplate

I have a component called Login, and these selectors:
const selectLogin = () => (state) => state.get('login');
const selectUser = () => createSelector(
selectLogin(),
(loginState) => loginState.get('user')
);
Here's what state looks like for the "login" component:
login: {
user: {
id: 206
}
}
In another component, I want to select the "user" object.
At the top of my file, I have
import { createStructuredSelector } from 'reselect';
import {
selectLogin,
selectUser
} from 'containers/Login/selectors';
const mapStateToProps = createStructuredSelector({
login: selectLogin(),
user: selectUser(),
});
When I use "selectUser()", I get "loginState.get is not a function".
If I remove all references to "selectUser()", I can access this.props.login.user. That works for me, but I want to know why I can't select from within the "login" state. The examples use the same "substate" convention in the selector, and they work. Any ideas?
Is this another component in another route?
You have to manually inject reducers and sagas required for the page in each route.
In route.js, loadReducer and inject it to the page, something like this:
{
path: '/projects/add',
...
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/Project/reducer'),
System.import('containers/Login/reducer')
...
]);
const renderRoute = loadModule(cb);
importModules.then(([projectReducer, loginReducer ...]) => {
injectReducer('projects', projectReducer.default);
injectReducer('login', projectReducer.default);
renderRoute(component);
});
importModules.catch(errorLoading);
},

Resources